ruffle/render/wgpu/src/blend.rs

84 lines
3.3 KiB
Rust
Raw Normal View History

use enum_map::Enum;
use swf::BlendMode;
#[derive(Enum, Debug, Copy, Clone)]
pub enum ComplexBlend {
Multiply, // Can't be trivial, 0 alpha is special case
Screen, // Can't be trivial. (dst + src) - (dst * src)
Lighten, // Might be trivial but I can't reproduce the right colors
Darken, // Might be trivial but I can't reproduce the right colors
Difference, // Can't be trivial, relies on abs operation
Invert, // May be trivial using a constant? Hard because it's without premultiplied alpha
Alpha, // Can't be trivial, requires layer tracking
Erase, // Can't be trivial, requires layer tracking
Overlay, // Can't be trivial, big math expression
HardLight, // Can't be trivial, big math expression
}
#[derive(Debug, Copy, Clone)]
pub enum BlendType {
/// Trivial blends can be expressed with just a "draw bitmap" with blend states
Trivial(TrivialBlend),
/// Complex blends require a shader to express, so they are separated out into their own render
Complex(ComplexBlend),
}
impl BlendType {
pub fn from(mode: BlendMode) -> BlendType {
match mode {
BlendMode::Normal => BlendType::Trivial(TrivialBlend::Normal),
BlendMode::Layer => BlendType::Trivial(TrivialBlend::Normal),
BlendMode::Multiply => BlendType::Complex(ComplexBlend::Multiply),
BlendMode::Screen => BlendType::Complex(ComplexBlend::Screen),
BlendMode::Lighten => BlendType::Complex(ComplexBlend::Lighten),
BlendMode::Darken => BlendType::Complex(ComplexBlend::Darken),
BlendMode::Difference => BlendType::Complex(ComplexBlend::Difference),
BlendMode::Add => BlendType::Trivial(TrivialBlend::Add),
BlendMode::Subtract => BlendType::Trivial(TrivialBlend::Subtract),
BlendMode::Invert => BlendType::Complex(ComplexBlend::Invert),
BlendMode::Alpha => BlendType::Complex(ComplexBlend::Alpha),
BlendMode::Erase => BlendType::Complex(ComplexBlend::Erase),
BlendMode::Overlay => BlendType::Complex(ComplexBlend::Overlay),
BlendMode::HardLight => BlendType::Complex(ComplexBlend::HardLight),
}
}
pub fn default_color(&self) -> wgpu::Color {
wgpu::Color::TRANSPARENT
}
}
#[derive(Enum, Debug, Copy, Clone)]
pub enum TrivialBlend {
Normal,
Add,
Subtract,
}
impl TrivialBlend {
pub fn blend_state(self) -> wgpu::BlendState {
// out = <src_factor> * src <operation> <dst_factor> * dst
match self {
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::Subtract => wgpu::BlendState {
color: wgpu::BlendComponent {
src_factor: wgpu::BlendFactor::One,
dst_factor: wgpu::BlendFactor::One,
operation: wgpu::BlendOperation::ReverseSubtract,
},
alpha: wgpu::BlendComponent::OVER,
},
}
}
}