diff --git a/render/wgpu/shaders/filter/bevel.wgsl b/render/wgpu/shaders/filter/bevel.wgsl new file mode 100644 index 000000000..1c7b7c257 --- /dev/null +++ b/render/wgpu/shaders/filter/bevel.wgsl @@ -0,0 +1,84 @@ +struct Filter { + highlight_color: vec4, + shadow_color: vec4, + strength: f32, + bevel_type: u32, + knockout: u32, + composite_source: u32, +} + +@group(0) @binding(0) var texture: texture_2d; +@group(0) @binding(1) var texture_sampler: sampler; +@group(0) @binding(2) var filter_args: Filter; +@group(0) @binding(3) var blurred: texture_2d; + +struct VertexOutput { + @builtin(position) position: vec4, + @location(0) source_uv: vec2, + @location(1) blur_uv_left: vec2, + @location(2) blur_uv_right: vec2, +}; + +struct VertexInput { + /// The position of the vertex in texture space (topleft 0,0, bottomright 1,1) + @location(0) position: vec2, + + /// The coordinate of the source texture to sample in texture space (topleft 0,0, bottomright 1,1) + @location(1) source_uv: vec2, + + /// The coordinate of the blur texture to sample in texture space (topleft 0,0, bottomright 1,1) + @location(2) blur_uv_left: vec2, + + /// The coordinate of the blur texture to sample in texture space (topleft 0,0, bottomright 1,1) + @location(3) blur_uv_right: vec2, +}; + +@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((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 { + 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; + } + } +} diff --git a/render/wgpu/src/backend.rs b/render/wgpu/src/backend.rs index 305168c08..4621bdf6a 100644 --- a/render/wgpu/src/backend.rs +++ b/render/wgpu/src/backend.rs @@ -810,6 +810,7 @@ impl RenderBackend for WgpuRenderBackend { | Filter::DropShadowFilter(_) | Filter::ColorMatrixFilter(_) | Filter::ShaderFilter(_) + | Filter::BevelFilter(_) ) } diff --git a/render/wgpu/src/filters.rs b/render/wgpu/src/filters.rs index d691d0b07..19afa0ded 100644 --- a/render/wgpu/src/filters.rs +++ b/render/wgpu/src/filters.rs @@ -1,3 +1,4 @@ +mod bevel; mod blur; mod color_matrix; mod drop_shadow; @@ -9,6 +10,7 @@ use std::sync::{Mutex, OnceLock}; use crate::buffer_pool::TexturePool; use crate::descriptors::Descriptors; +use crate::filters::bevel::BevelFilter; use crate::filters::blur::BlurFilter; use crate::filters::color_matrix::ColorMatrixFilter; use crate::filters::drop_shadow::DropShadowFilter; @@ -130,6 +132,73 @@ impl<'a> FilterSource<'a> { 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 { @@ -137,6 +206,7 @@ pub struct Filters { pub color_matrix: ColorMatrixFilter, pub shader: ShaderFilter, pub glow: GlowFilter, + pub bevel: BevelFilter, } impl Filters { @@ -146,6 +216,7 @@ impl Filters { color_matrix: ColorMatrixFilter::new(device), shader: ShaderFilter::new(), glow: GlowFilter::new(device), + bevel: BevelFilter::new(device), } } @@ -163,6 +234,10 @@ impl Filters { Filter::DropShadowFilter(filter) => { 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, } } @@ -215,10 +290,17 @@ impl Filters { &self.blur, &self.glow, )), + Filter::BevelFilter(filter) => Some(descriptors.filters.bevel.apply( + descriptors, + texture_pool, + draw_encoder, + &source, + &filter, + &self.blur, + )), filter => { static WARNED_FILTERS: OnceLock>> = OnceLock::new(); let name = match filter { - Filter::BevelFilter(_) => "BevelFilter", Filter::GradientGlowFilter(_) => "GradientGlowFilter", Filter::GradientBevelFilter(_) => "GradientBevelFilter", Filter::ConvolutionFilter(_) => "ConvolutionFilter", @@ -227,6 +309,7 @@ impl Filters { | Filter::BlurFilter(_) | Filter::GlowFilter(_) | Filter::DropShadowFilter(_) + | Filter::BevelFilter(_) | Filter::ShaderFilter(_) => unreachable!(), }; // Only warn once per filter type @@ -297,3 +380,24 @@ pub const VERTEX_BUFFERS_DESCRIPTION_FILTERS_WITH_BLUR: [wgpu::VertexBufferLayou 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::() as u64, + step_mode: wgpu::VertexStepMode::Vertex, + attributes: &vertex_attr_array![ + 0 => Float32x2, + 1 => Float32x2, + 2 => Float32x2, + 3 => Float32x2, + ], + }]; diff --git a/render/wgpu/src/filters/bevel.rs b/render/wgpu/src/filters/bevel.rs new file mode 100644 index 000000000..69fcad410 --- /dev/null +++ b/render/wgpu/src/filters/bevel.rs @@ -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>, +} + +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::() 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, + blur_filter: &BlurFilter, + ) -> Rectangle { + 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 + } +} diff --git a/render/wgpu/src/shaders.rs b/render/wgpu/src/shaders.rs index fe5c24321..e5b631f75 100644 --- a/render/wgpu/src/shaders.rs +++ b/render/wgpu/src/shaders.rs @@ -24,6 +24,7 @@ pub struct Shaders { pub color_matrix_filter: wgpu::ShaderModule, pub blur_filter: wgpu::ShaderModule, pub glow_filter: wgpu::ShaderModule, + pub bevel_filter: wgpu::ShaderModule, } impl Shaders { @@ -95,6 +96,13 @@ impl 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( device, &mut composer, @@ -126,6 +134,7 @@ impl Shaders { color_matrix_filter, blur_filter, glow_filter, + bevel_filter, } } } diff --git a/tests/tests/swfs/visual/filters/bevel/expected.png b/tests/tests/swfs/visual/filters/bevel/expected.png new file mode 100644 index 000000000..7c50519a4 Binary files /dev/null and b/tests/tests/swfs/visual/filters/bevel/expected.png differ diff --git a/tests/tests/swfs/visual/filters/bevel/output.txt b/tests/tests/swfs/visual/filters/bevel/output.txt new file mode 100644 index 000000000..e69de29bb diff --git a/tests/tests/swfs/visual/filters/bevel/test.fla b/tests/tests/swfs/visual/filters/bevel/test.fla new file mode 100644 index 000000000..1cec8ab94 Binary files /dev/null and b/tests/tests/swfs/visual/filters/bevel/test.fla differ diff --git a/tests/tests/swfs/visual/filters/bevel/test.swf b/tests/tests/swfs/visual/filters/bevel/test.swf new file mode 100644 index 000000000..9d7c1d340 Binary files /dev/null and b/tests/tests/swfs/visual/filters/bevel/test.swf differ diff --git a/tests/tests/swfs/visual/filters/bevel/test.toml b/tests/tests/swfs/visual/filters/bevel/test.toml new file mode 100644 index 000000000..78377bb10 --- /dev/null +++ b/tests/tests/swfs/visual/filters/bevel/test.toml @@ -0,0 +1,7 @@ +num_frames = 1 + +[image_comparison] +tolerance = 3 + +[player_options] +with_renderer = { optional = false, sample_count = 1 } diff --git a/tests/tests/swfs/visual/filters/bevel_full/expected.png b/tests/tests/swfs/visual/filters/bevel_full/expected.png new file mode 100644 index 000000000..630982050 Binary files /dev/null and b/tests/tests/swfs/visual/filters/bevel_full/expected.png differ diff --git a/tests/tests/swfs/visual/filters/bevel_full/output.txt b/tests/tests/swfs/visual/filters/bevel_full/output.txt new file mode 100644 index 000000000..e69de29bb diff --git a/tests/tests/swfs/visual/filters/bevel_full/test.fla b/tests/tests/swfs/visual/filters/bevel_full/test.fla new file mode 100644 index 000000000..3c3e5c028 Binary files /dev/null and b/tests/tests/swfs/visual/filters/bevel_full/test.fla differ diff --git a/tests/tests/swfs/visual/filters/bevel_full/test.swf b/tests/tests/swfs/visual/filters/bevel_full/test.swf new file mode 100644 index 000000000..ab235e6b9 Binary files /dev/null and b/tests/tests/swfs/visual/filters/bevel_full/test.swf differ diff --git a/tests/tests/swfs/visual/filters/bevel_full/test.toml b/tests/tests/swfs/visual/filters/bevel_full/test.toml new file mode 100644 index 000000000..78377bb10 --- /dev/null +++ b/tests/tests/swfs/visual/filters/bevel_full/test.toml @@ -0,0 +1,7 @@ +num_frames = 1 + +[image_comparison] +tolerance = 3 + +[player_options] +with_renderer = { optional = false, sample_count = 1 } diff --git a/tests/tests/swfs/visual/filters/bevel_inner/expected.png b/tests/tests/swfs/visual/filters/bevel_inner/expected.png new file mode 100644 index 000000000..5fa4176af Binary files /dev/null and b/tests/tests/swfs/visual/filters/bevel_inner/expected.png differ diff --git a/tests/tests/swfs/visual/filters/bevel_inner/output.txt b/tests/tests/swfs/visual/filters/bevel_inner/output.txt new file mode 100644 index 000000000..e69de29bb diff --git a/tests/tests/swfs/visual/filters/bevel_inner/test.fla b/tests/tests/swfs/visual/filters/bevel_inner/test.fla new file mode 100644 index 000000000..7d9a4f533 Binary files /dev/null and b/tests/tests/swfs/visual/filters/bevel_inner/test.fla differ diff --git a/tests/tests/swfs/visual/filters/bevel_inner/test.swf b/tests/tests/swfs/visual/filters/bevel_inner/test.swf new file mode 100644 index 000000000..27e21ee00 Binary files /dev/null and b/tests/tests/swfs/visual/filters/bevel_inner/test.swf differ diff --git a/tests/tests/swfs/visual/filters/bevel_inner/test.toml b/tests/tests/swfs/visual/filters/bevel_inner/test.toml new file mode 100644 index 000000000..78377bb10 --- /dev/null +++ b/tests/tests/swfs/visual/filters/bevel_inner/test.toml @@ -0,0 +1,7 @@ +num_frames = 1 + +[image_comparison] +tolerance = 3 + +[player_options] +with_renderer = { optional = false, sample_count = 1 } diff --git a/tests/tests/swfs/visual/filters/bevel_outer/expected.png b/tests/tests/swfs/visual/filters/bevel_outer/expected.png new file mode 100644 index 000000000..1b425b9c4 Binary files /dev/null and b/tests/tests/swfs/visual/filters/bevel_outer/expected.png differ diff --git a/tests/tests/swfs/visual/filters/bevel_outer/output.txt b/tests/tests/swfs/visual/filters/bevel_outer/output.txt new file mode 100644 index 000000000..e69de29bb diff --git a/tests/tests/swfs/visual/filters/bevel_outer/test.fla b/tests/tests/swfs/visual/filters/bevel_outer/test.fla new file mode 100644 index 000000000..f327fc3a6 Binary files /dev/null and b/tests/tests/swfs/visual/filters/bevel_outer/test.fla differ diff --git a/tests/tests/swfs/visual/filters/bevel_outer/test.swf b/tests/tests/swfs/visual/filters/bevel_outer/test.swf new file mode 100644 index 000000000..04d753e9d Binary files /dev/null and b/tests/tests/swfs/visual/filters/bevel_outer/test.swf differ diff --git a/tests/tests/swfs/visual/filters/bevel_outer/test.toml b/tests/tests/swfs/visual/filters/bevel_outer/test.toml new file mode 100644 index 000000000..78377bb10 --- /dev/null +++ b/tests/tests/swfs/visual/filters/bevel_outer/test.toml @@ -0,0 +1,7 @@ +num_frames = 1 + +[image_comparison] +tolerance = 3 + +[player_options] +with_renderer = { optional = false, sample_count = 1 }