wgpu: Made Multiply, Add and Subtract blend modes use bitmap+blend

This commit is contained in:
Nathan Adams 2022-12-23 02:11:45 +01:00
parent e69d76fa41
commit f253abdbd1
4 changed files with 52 additions and 30 deletions

View File

@ -26,9 +26,6 @@ fn main_vertex(in: VertexInput) -> VertexOutput {
fn blend_func(src: vec3<f32>, dst: vec3<f32>) -> vec3<f32> { fn blend_func(src: vec3<f32>, dst: vec3<f32>) -> vec3<f32> {
switch (blend.mode) { switch (blend.mode) {
case 1: { // Multiply
return src * dst;
}
case 2: { // Screen case 2: { // Screen
return (dst + src) - (dst * src); return (dst + src) - (dst * src);
} }
@ -72,11 +69,7 @@ fn main_fragment(in: VertexOutput) -> @location(0) vec4<f32> {
var src: vec4<f32> = textureSample(current_texture, texture_sampler, in.uv); var src: vec4<f32> = textureSample(current_texture, texture_sampler, in.uv);
if (src.a > 0.0) { if (src.a > 0.0) {
if (blend.mode == 6) { // Add if (blend.mode == 9) { // Alpha
return src + dst;
} else if (blend.mode == 7) { // Subtract
return vec4<f32>(dst.rgb - src.rgb, src.a + dst.a);
} else if (blend.mode == 9) { // Alpha
return vec4<f32>(dst.rgb * src.a, src.a * dst.a); return vec4<f32>(dst.rgb * src.a, src.a * dst.a);
} else if (blend.mode == 10) { // Erase } else if (blend.mode == 10) { // Erase
return vec4<f32>(dst.rgb * (1.0 - src.a), (1.0 - src.a) * dst.a); return vec4<f32>(dst.rgb * (1.0 - src.a), (1.0 - src.a) * dst.a);

View File

@ -761,7 +761,7 @@ fn chunk_blends<'a>(
wgpu::TextureFormat::Rgba8Unorm, wgpu::TextureFormat::Rgba8Unorm,
); );
let target = surface.draw_commands( let target = surface.draw_commands(
Some(wgpu::Color::TRANSPARENT), Some(BlendType::from(*blend_mode).default_color()),
&descriptors, &descriptors,
&meshes, &meshes,
commands, commands,

View File

@ -30,13 +30,10 @@ impl Descriptors {
let quad = Quad::new(&device); let quad = Quad::new(&device);
let blend_buffers = enum_map! { let blend_buffers = enum_map! {
ComplexBlend::Multiply => 1,
ComplexBlend::Screen => 2, ComplexBlend::Screen => 2,
ComplexBlend::Lighten => 3, ComplexBlend::Lighten => 3,
ComplexBlend::Darken => 4, ComplexBlend::Darken => 4,
ComplexBlend::Difference => 5, ComplexBlend::Difference => 5,
ComplexBlend::Add => 6,
ComplexBlend::Subtract => 7,
ComplexBlend::Invert => 8, ComplexBlend::Invert => 8,
ComplexBlend::Alpha => 9, ComplexBlend::Alpha => 9,
ComplexBlend::Erase => 10, ComplexBlend::Erase => 10,

View File

@ -23,34 +23,31 @@ pub struct ShapePipeline {
#[derive(Enum, Debug, Copy, Clone)] #[derive(Enum, Debug, Copy, Clone)]
pub enum TrivialBlend { pub enum TrivialBlend {
Normal, Normal,
Multiply,
Add,
Subtract,
} }
#[derive(Enum, Debug, Copy, Clone)] #[derive(Enum, Debug, Copy, Clone)]
pub enum ComplexBlend { pub enum ComplexBlend {
Multiply, Screen, // Can't be trivial. (dst + src) - (dst * src)
Screen, Lighten, // Might be trivial but I can't reproduce the right colors
Lighten, Darken, // Might be trivial but I can't reproduce the right colors
Darken, Difference, // Can't be trivial, relies on abs operation
Difference, Invert, // May be trivial using a constant? Hard because it's without premultiplied alpha
Add, Alpha, // Can't be trivial, requires layer tracking
Subtract, Erase, // Can't be trivial, requires layer tracking
Invert, Overlay, // Can't be trivial, big math expression
Alpha, HardLight, // Can't be trivial, big math expression
Erase,
Overlay,
HardLight,
} }
impl ComplexBlend { impl ComplexBlend {
pub fn id(&self) -> i32 { pub fn id(&self) -> i32 {
match self { match self {
ComplexBlend::Multiply => 1,
ComplexBlend::Screen => 2, ComplexBlend::Screen => 2,
ComplexBlend::Lighten => 3, ComplexBlend::Lighten => 3,
ComplexBlend::Darken => 4, ComplexBlend::Darken => 4,
ComplexBlend::Difference => 5, ComplexBlend::Difference => 5,
ComplexBlend::Add => 6,
ComplexBlend::Subtract => 7,
ComplexBlend::Invert => 8, ComplexBlend::Invert => 8,
ComplexBlend::Alpha => 9, ComplexBlend::Alpha => 9,
ComplexBlend::Erase => 10, ComplexBlend::Erase => 10,
@ -62,7 +59,10 @@ impl ComplexBlend {
#[derive(Debug, Copy, Clone)] #[derive(Debug, Copy, Clone)]
pub enum BlendType { pub enum BlendType {
/// Trivial blends can be expressed with just a "draw bitmap" with blend states
Trivial(TrivialBlend), Trivial(TrivialBlend),
/// Complex blends require a shader to express, so they are separated out into their own render
Complex(ComplexBlend), Complex(ComplexBlend),
} }
@ -71,13 +71,13 @@ impl BlendType {
match mode { match mode {
BlendMode::Normal => BlendType::Trivial(TrivialBlend::Normal), BlendMode::Normal => BlendType::Trivial(TrivialBlend::Normal),
BlendMode::Layer => BlendType::Trivial(TrivialBlend::Normal), BlendMode::Layer => BlendType::Trivial(TrivialBlend::Normal),
BlendMode::Multiply => BlendType::Complex(ComplexBlend::Multiply), BlendMode::Multiply => BlendType::Trivial(TrivialBlend::Multiply),
BlendMode::Screen => BlendType::Complex(ComplexBlend::Screen), BlendMode::Screen => BlendType::Complex(ComplexBlend::Screen),
BlendMode::Lighten => BlendType::Complex(ComplexBlend::Lighten), BlendMode::Lighten => BlendType::Complex(ComplexBlend::Lighten),
BlendMode::Darken => BlendType::Complex(ComplexBlend::Darken), BlendMode::Darken => BlendType::Complex(ComplexBlend::Darken),
BlendMode::Difference => BlendType::Complex(ComplexBlend::Difference), BlendMode::Difference => BlendType::Complex(ComplexBlend::Difference),
BlendMode::Add => BlendType::Complex(ComplexBlend::Add), BlendMode::Add => BlendType::Trivial(TrivialBlend::Add),
BlendMode::Subtract => BlendType::Complex(ComplexBlend::Subtract), BlendMode::Subtract => BlendType::Trivial(TrivialBlend::Subtract),
BlendMode::Invert => BlendType::Complex(ComplexBlend::Invert), BlendMode::Invert => BlendType::Complex(ComplexBlend::Invert),
BlendMode::Alpha => BlendType::Complex(ComplexBlend::Alpha), BlendMode::Alpha => BlendType::Complex(ComplexBlend::Alpha),
BlendMode::Erase => BlendType::Complex(ComplexBlend::Erase), BlendMode::Erase => BlendType::Complex(ComplexBlend::Erase),
@ -85,6 +85,13 @@ impl BlendType {
BlendMode::HardLight => BlendType::Complex(ComplexBlend::HardLight), BlendMode::HardLight => BlendType::Complex(ComplexBlend::HardLight),
} }
} }
pub fn default_color(&self) -> wgpu::Color {
match self {
BlendType::Trivial(TrivialBlend::Multiply) => wgpu::Color::WHITE,
_ => wgpu::Color::TRANSPARENT,
}
}
} }
#[derive(Debug)] #[derive(Debug)]
@ -178,7 +185,32 @@ impl Pipelines {
let bitmap_pipelines: [ShapePipeline; TrivialBlend::LENGTH] = (0..TrivialBlend::LENGTH) let bitmap_pipelines: [ShapePipeline; TrivialBlend::LENGTH] = (0..TrivialBlend::LENGTH)
.map(|blend| { .map(|blend| {
let blend = match TrivialBlend::from_usize(blend) { let blend = match TrivialBlend::from_usize(blend) {
// out = <src_factor> * src <operation> <dst_factor> * dst
TrivialBlend::Normal => wgpu::BlendState::PREMULTIPLIED_ALPHA_BLENDING, TrivialBlend::Normal => wgpu::BlendState::PREMULTIPLIED_ALPHA_BLENDING,
TrivialBlend::Add => wgpu::BlendState {
color: wgpu::BlendComponent {
src_factor: wgpu::BlendFactor::One,
dst_factor: wgpu::BlendFactor::One,
operation: wgpu::BlendOperation::Add,
},
alpha: wgpu::BlendComponent::OVER,
},
TrivialBlend::Multiply => wgpu::BlendState {
color: wgpu::BlendComponent {
src_factor: wgpu::BlendFactor::Dst,
dst_factor: wgpu::BlendFactor::Zero,
operation: wgpu::BlendOperation::Add,
},
alpha: wgpu::BlendComponent::OVER,
},
TrivialBlend::Subtract => wgpu::BlendState {
color: wgpu::BlendComponent {
src_factor: wgpu::BlendFactor::One,
dst_factor: wgpu::BlendFactor::One,
operation: wgpu::BlendOperation::ReverseSubtract,
},
alpha: wgpu::BlendComponent::OVER,
},
}; };
let name = format!("Bitmap ({blend:?})"); let name = format!("Bitmap ({blend:?})");
create_shape_pipeline( create_shape_pipeline(