#![allow(non_snake_case)]
use crate::*;
pub trait Blend {
fn blend(src: u32, dst: u32) -> u32;
}
pub struct Dst;
impl Blend for Dst {
#[inline]
fn blend(_src: u32, dst: u32) -> u32 {
dst
}
}
pub struct Src;
impl Blend for Src {
#[inline]
fn blend(src: u32, _dst: u32) -> u32 {
src
}
}
pub struct Clear;
impl Blend for Clear {
#[inline]
fn blend(_src: u32, _dst: u32) -> u32 {
0
}
}
pub struct SrcOver;
impl Blend for SrcOver {
#[inline]
fn blend(src: u32, dst: u32) -> u32 {
over(src, dst)
}
}
pub struct DstOver;
impl Blend for DstOver {
#[inline]
fn blend(src: u32, dst: u32) -> u32 {
over(dst, src)
}
}
pub struct SrcIn;
impl Blend for SrcIn {
#[inline]
fn blend(src: u32, dst: u32) -> u32 {
alpha_mul(src, alpha_to_alpha256(packed_alpha(dst)))
}
}
pub struct DstIn;
impl Blend for DstIn {
#[inline]
fn blend(src: u32, dst: u32) -> u32 {
alpha_mul(dst, alpha_to_alpha256(packed_alpha(src)))
}
}
pub struct SrcOut;
impl Blend for SrcOut {
#[inline]
fn blend(src: u32, dst: u32) -> u32 {
alpha_mul(src, alpha_to_alpha256(255 - packed_alpha(dst)))
}
}
pub struct DstOut;
impl Blend for DstOut {
#[inline]
fn blend(src: u32, dst: u32) -> u32 {
alpha_mul(dst, alpha_to_alpha256(255 - packed_alpha(src)))
}
}
pub struct SrcAtop;
impl Blend for SrcAtop {
#[inline]
fn blend(src: u32, dst: u32) -> u32 {
let sa = packed_alpha(src);
let da = packed_alpha(dst);
let isa = 255 - sa;
pack_argb32(
da,
muldiv255(da, get_packed_r32(src)) + muldiv255(isa, get_packed_r32(dst)),
muldiv255(da, get_packed_g32(src)) + muldiv255(isa, get_packed_g32(dst)),
muldiv255(da, get_packed_b32(src)) + muldiv255(isa, get_packed_b32(dst))
)
}
}
pub struct DstAtop;
impl Blend for DstAtop {
#[inline]
fn blend(src: u32, dst: u32) -> u32 {
let sa = packed_alpha(src);
let da = packed_alpha(dst);
let ida = 255 - da;
pack_argb32(
sa,
muldiv255(ida, get_packed_r32(src)) + muldiv255(sa, get_packed_r32(dst)),
muldiv255(ida, get_packed_g32(src)) + muldiv255(sa, get_packed_g32(dst)),
muldiv255(ida, get_packed_b32(src)) + muldiv255(sa, get_packed_b32(dst))
)
}
}
pub struct Xor;
impl Blend for Xor {
#[inline]
fn blend(src: u32, dst: u32) -> u32 {
let sa = packed_alpha(src);
let da = packed_alpha(dst);
let isa = 255 - sa;
let ida = 255 - da;
pack_argb32(
sa + da - (muldiv255(sa, da) * 2),
muldiv255(ida, get_packed_r32(src)) + muldiv255(isa, get_packed_r32(dst)),
muldiv255(ida, get_packed_g32(src)) + muldiv255(isa, get_packed_g32(dst)),
muldiv255(ida, get_packed_b32(src)) + muldiv255(isa, get_packed_b32(dst))
)
}
}
fn saturated_add(a: u32, b: u32) -> u32 {
debug_assert!(a <= 255);
debug_assert!(b <= 255);
let sum = a + b;
if sum > 255 {
255
} else {
sum
}
}
pub struct Add;
impl Blend for Add {
#[inline]
fn blend(src: u32, dst: u32) -> u32 {
pack_argb32(
saturated_add(get_packed_a32(src), get_packed_a32(dst)),
saturated_add(get_packed_r32(src), get_packed_r32(dst)),
saturated_add(get_packed_g32(src), get_packed_g32(dst)),
saturated_add(get_packed_b32(src), get_packed_b32(dst))
)
}
}
fn blendfunc_multiply_byte(sc: i32, dc: i32, sa: i32, da: i32) -> u32 {
clamp_div255round(sc * (255 - da) + dc * (255 - sa) + sc * dc)
}
pub struct Multiply;
impl Blend for Multiply {
fn blend(src: u32, dst: u32) -> u32 {
let sa = get_packed_a32(src) as i32;
let da = get_packed_a32(dst) as i32;
pack_argb32(
srcover_byte(get_packed_a32(src), get_packed_a32(dst)),
blendfunc_multiply_byte(get_packed_r32(src) as i32, get_packed_r32(dst) as i32, sa, da),
blendfunc_multiply_byte(get_packed_g32(src) as i32, get_packed_g32(dst) as i32, sa, da),
blendfunc_multiply_byte(get_packed_b32(src) as i32, get_packed_b32(dst) as i32, sa, da)
)
}
}
#[inline]
fn srcover_byte(a: u32, b: u32) -> u32 {
a + b - muldiv255(a, b)
}
pub struct Screen;
impl Blend for Screen {
#[inline]
fn blend(src: u32, dst: u32) -> u32 {
pack_argb32(
srcover_byte(get_packed_a32(src), get_packed_a32(dst)),
srcover_byte(get_packed_r32(src), get_packed_r32(dst)),
srcover_byte(get_packed_g32(src), get_packed_g32(dst)),
srcover_byte(get_packed_b32(src), get_packed_b32(dst))
)
}
}
fn clamp_div255round(prod: i32) -> u32 {
if prod <= 0 {
0
} else if prod >= 255 * 255 {
255
} else {
div255(prod as u32)
}
}
fn overlay_byte(sc: u32, dc: u32, sa: u32, da: u32) -> u32 {
let tmp = sc * (255 - da) + dc * (255 - sa);
let rc;
if 2 * dc <= da {
rc = 2 * sc * dc;
} else {
rc = sa * da - 2 * (da - dc) * (sa - sc);
}
clamp_div255round((rc + tmp) as i32)
}
pub struct Overlay;
impl Blend for Overlay {
fn blend(src: u32, dst: u32) -> u32 {
let sa = get_packed_a32(src);
let da = get_packed_a32(dst);
pack_argb32(
srcover_byte(sa, da),
overlay_byte(get_packed_r32(src), get_packed_r32(dst), sa, da),
overlay_byte(get_packed_g32(src), get_packed_g32(dst), sa, da),
overlay_byte(get_packed_b32(src), get_packed_b32(dst), sa, da)
)
}
}
fn darken_byte(sc: u32, dc: u32, sa: u32, da: u32) -> u32 {
let sd = sc * da;
let ds = dc * sa;
if sd < ds {
sc + dc - div255(ds)
} else {
dc + sc - div255(sd)
}
}
pub struct Darken;
impl Blend for Darken {
fn blend(src: u32, dst: u32) -> u32 {
let sa = get_packed_a32(src);
let da = get_packed_a32(dst);
pack_argb32(
srcover_byte(sa, da),
darken_byte(get_packed_r32(src), get_packed_r32(dst), sa, da),
darken_byte(get_packed_g32(src), get_packed_g32(dst), sa, da),
darken_byte(get_packed_b32(src), get_packed_b32(dst), sa, da)
)
}
}
fn lighten_byte(sc: u32, dc: u32, sa: u32, da: u32) -> u32 {
let sd = sc * da;
let ds = dc * sa;
if sd > ds {
sc + dc - div255(ds)
} else {
dc + sc - div255(sd)
}
}
pub struct Lighten;
impl Blend for Lighten {
fn blend(src: u32, dst: u32) -> u32 {
let sa = get_packed_a32(src);
let da = get_packed_a32(dst);
pack_argb32(
srcover_byte(sa, da),
lighten_byte(get_packed_r32(src), get_packed_r32(dst), sa, da),
lighten_byte(get_packed_g32(src), get_packed_g32(dst), sa, da),
lighten_byte(get_packed_b32(src), get_packed_b32(dst), sa, da)
)
}
}
fn colordodge_byte(sc: i32, dc: i32, sa: i32, da: i32) -> u32 {
let mut diff = sa - sc;
let rc = if 0 == dc {
return muldiv255(sc as u32, (255 - da) as u32);
} else if 0 == diff {
sa * da + sc * (255 - da) + dc * (255 - sa)
} else {
diff = (dc * sa) / diff;
sa * (if da < diff { da } else { diff }) + sc * (255 - da) + dc * (255 - sa)
};
clamp_div255round(rc)
}
pub struct ColorDodge;
impl Blend for ColorDodge {
fn blend(src: u32, dst: u32) -> u32 {
let sa = get_packed_a32(src) as i32;
let da = get_packed_a32(dst) as i32;
pack_argb32(
srcover_byte(sa as u32, da as u32),
colordodge_byte(get_packed_r32(src) as i32, get_packed_r32(dst) as i32, sa, da),
colordodge_byte(get_packed_g32(src) as i32, get_packed_g32(dst) as i32, sa, da),
colordodge_byte(get_packed_b32(src) as i32, get_packed_b32(dst) as i32, sa, da)
)
}
}
fn colorburn_byte(sc: i32, dc: i32, sa: i32, da: i32) -> u32 {
let rc = if dc == da {
sa * da + sc * (255 - da) + dc * (255 - sa)
} else if 0 == sc {
return muldiv255(dc as u32, (255 - sa) as u32);
} else {
let tmp = (da - dc) * sa / sc;
sa * (da - (if da < tmp { da } else { tmp }))
+ sc * (255 - da) + dc * (255 - sa)
};
clamp_div255round(rc)
}
pub struct ColorBurn;
impl Blend for ColorBurn {
fn blend(src: u32, dst: u32) -> u32 {
let sa = get_packed_a32(src) as i32;
let da = get_packed_a32(dst) as i32;
pack_argb32(
srcover_byte(sa as u32, da as u32),
colorburn_byte(get_packed_r32(src) as i32, get_packed_r32(dst) as i32, sa, da),
colorburn_byte(get_packed_g32(src) as i32, get_packed_g32(dst) as i32, sa, da),
colorburn_byte(get_packed_b32(src) as i32, get_packed_b32(dst) as i32, sa, da)
)
}
}
fn hardlight_byte(sc: i32, dc: i32, sa: i32, da: i32) -> u32 {
let rc = if 2 * sc <= sa {
2 * sc * dc
} else {
sa * da - 2 * (da - dc) * (sa - sc)
};
clamp_div255round(rc + sc * (255 - da) + dc * (255 - sa))
}
pub struct HardLight;
impl Blend for HardLight {
fn blend(src: u32, dst: u32) -> u32 {
let sa = get_packed_a32(src) as i32;
let da = get_packed_a32(dst) as i32;
pack_argb32(
srcover_byte(sa as u32, da as u32),
hardlight_byte(get_packed_r32(src) as i32, get_packed_r32(dst) as i32, sa, da),
hardlight_byte(get_packed_g32(src) as i32, get_packed_g32(dst) as i32, sa, da),
hardlight_byte(get_packed_b32(src) as i32, get_packed_b32(dst) as i32, sa, da)
)
}
}
fn sqrt_bits(x: i32, count: i32) -> i32 {
debug_assert!(x >= 0 && count > 0 && count <= 30);
let mut root = 0;
let mut rem_hi = 0;
let mut rem_lo = x;
loop {
root <<= 1;
rem_hi = (rem_hi << 2) | (rem_lo >> 30);
rem_lo <<= 2;
let test_div = (root << 1) + 1;
if rem_hi >= test_div {
rem_hi -= test_div;
root += 1;
}
if -count < 0 {
break;
}
}
root
}
type U8Cpu = u32;
fn sqrt_unit_byte(n: U8Cpu) -> U8Cpu {
sqrt_bits(n as i32, 15 + 4) as u32
}
fn softlight_byte(sc: i32, dc: i32, sa: i32, da: i32) -> u32 {
let m = if da != 0 { dc * 256 / da } else { 0 };
let rc = if 2 * sc <= sa {
dc * (sa + ((2 * sc - sa) * (256 - m) >> 8))
} else if 4 * dc <= da {
let tmp = (4 * m * (4 * m + 256) * (m - 256) >> 16) + 7 * m;
dc * sa + (da * (2 * sc - sa) * tmp >> 8)
} else {
let tmp = sqrt_unit_byte(m as u32) as i32 - m;
dc * sa + (da * (2 * sc - sa) * tmp >> 8)
};
clamp_div255round(rc + sc * (255 - da) + dc * (255 - sa))
}
pub struct SoftLight;
impl Blend for SoftLight {
fn blend(src: u32, dst: u32) -> u32 {
let sa = get_packed_a32(src) as i32;
let da = get_packed_a32(dst) as i32;
pack_argb32(
srcover_byte(sa as u32, da as u32),
softlight_byte(get_packed_r32(src) as i32, get_packed_r32(dst) as i32, sa, da),
softlight_byte(get_packed_g32(src) as i32, get_packed_g32(dst) as i32, sa, da),
softlight_byte(get_packed_b32(src) as i32, get_packed_b32(dst) as i32, sa, da)
)
}
}
fn clamp_signed_byte(n: i32) -> u32 {
if n < 0 {
0
} else if n > 255 {
255
} else {
n as u32
}
}
fn difference_byte(sc: i32, dc: i32, sa: i32, da: i32) -> u32 {
let tmp = (sc * da).min(dc * sa);
clamp_signed_byte(sc + dc - 2 * div255(tmp as u32) as i32)
}
pub struct Difference;
impl Blend for Difference {
fn blend(src: u32, dst: u32) -> u32 {
let sa = get_packed_a32(src) as i32;
let da = get_packed_a32(dst) as i32;
pack_argb32(
srcover_byte(sa as u32, da as u32),
difference_byte(get_packed_r32(src) as i32, get_packed_r32(dst) as i32, sa, da),
difference_byte(get_packed_g32(src) as i32, get_packed_g32(dst) as i32, sa, da),
difference_byte(get_packed_b32(src) as i32, get_packed_b32(dst) as i32, sa, da)
)
}
}
fn exclusion_byte(sc: i32, dc: i32, _sa: i32, _da: i32) -> u32 {
let r = 255 * (sc + dc) - 2 * sc * dc;
clamp_div255round(r)
}
pub struct Exclusion;
impl Blend for Exclusion {
fn blend(src: u32, dst: u32) -> u32 {
let sa = get_packed_a32(src) as i32;
let da = get_packed_a32(dst) as i32;
pack_argb32(
srcover_byte(sa as u32, da as u32),
exclusion_byte(get_packed_r32(src) as i32, get_packed_r32(dst) as i32, sa, da),
exclusion_byte(get_packed_g32(src) as i32, get_packed_g32(dst) as i32, sa, da),
exclusion_byte(get_packed_b32(src) as i32, get_packed_b32(dst) as i32, sa, da)
)
}
}
fn lum(r: i32, g: i32, b: i32) -> i32 {
div255((r * 77 + g * 150 + b * 28) as u32) as i32
}
fn mul_div(numer1: i32, numer2: i32, denom: i32) -> i32 {
((numer1 as i64 * numer2 as i64) / denom as i64) as i32
}
fn minimum(a: i32, b: i32, c: i32) -> i32 {
a.min(b).min(c)
}
fn maximum(a: i32, b: i32, c: i32) -> i32 {
a.max(b).max(c)
}
fn clip_color(r: &mut i32, g: &mut i32, b: &mut i32, a: i32) {
let L = lum(*r, *g, *b);
let n = minimum(*r, *g, *b);
let x = maximum(*r, *g, *b);
let denom = L - n;
if (n < 0) && (denom != 0) { *r = L + mul_div(*r - L, L, denom);
*g = L + mul_div(*g - L, L, denom);
*b = L + mul_div(*b - L, L, denom);
}
let denom = x - L;
if (x > a) && (denom != 0) { let numer = a - L;
*r = L + mul_div(*r - L, numer, denom);
*g = L + mul_div(*g - L, numer, denom);
*b = L + mul_div(*b - L, numer, denom);
}
}
fn sat(r: i32, g: i32, b: i32) -> i32 {
maximum(r, g, b) - minimum(r, g, b)
}
fn set_saturation_components(cmin: &mut i32, cmind: &mut i32, cmax: &mut i32, s: i32) {
if *cmax > *cmin {
*cmind = mul_div(*cmind - *cmin, s, *cmax - *cmin);
*cmax = s;
} else {
*cmax = 0;
*cmind = 0;
}
*cmin = 0;
}
fn set_sat(r: &mut i32, g: &mut i32, b: &mut i32, s: i32) {
if *r <= *g {
if *g <= *b {
set_saturation_components(r, g, b, s);
} else if *r <= *b {
set_saturation_components(r, b, g, s);
} else {
set_saturation_components(b, r, g, s);
}
} else if *r <= *b {
set_saturation_components(g, r, b, s);
} else if *g <= *b {
set_saturation_components(g, b, r, s);
} else {
set_saturation_components(b, g, r, s);
}
}
fn set_lum(r: &mut i32, g: &mut i32, b: &mut i32, a: i32, l: i32) {
let d = l - lum(*r, *g, *b);
*r += d;
*g += d;
*b += d;
clip_color(r, g, b, a);
}
fn blendfunc_nonsep_byte(sc: i32, dc: i32, sa: i32, da: i32, blendval: i32) -> u32 {
clamp_div255round(sc * (255 - da) + dc * (255 - sa) + blendval)
}
pub struct Hue;
impl Blend for Hue {
fn blend(src: u32, dst: u32) -> u32 {
let sr = get_packed_r32(src) as i32;
let sg = get_packed_g32(src) as i32;
let sb = get_packed_b32(src) as i32;
let sa = get_packed_a32(src) as i32;
let dr = get_packed_r32(dst) as i32;
let dg = get_packed_g32(dst) as i32;
let db = get_packed_b32(dst) as i32;
let da = get_packed_a32(dst) as i32;
let mut Sr;
let mut Sg;
let mut Sb;
if sa != 0 && da != 0 {
Sr = sr * sa;
Sg = sg * sa;
Sb = sb * sa;
set_sat(&mut Sr, &mut Sg, &mut Sb, sat(dr, dg, db) * sa);
set_lum(&mut Sr, &mut Sg, &mut Sb, sa * da, lum(dr, dg, db) * sa);
} else {
Sr = 0;
Sg = 0;
Sb = 0;
}
pack_argb32(
srcover_byte(sa as u32, da as u32),
blendfunc_nonsep_byte(sr, dr, sa, da, Sr),
blendfunc_nonsep_byte(sg, dg, sa, da, Sg),
blendfunc_nonsep_byte(sb, db, sa, da, Sb)
)
}
}
pub struct Saturation;
impl Blend for Saturation {
fn blend(src: u32, dst: u32) -> u32 {
let sr = get_packed_r32(src) as i32;
let sg = get_packed_g32(src) as i32;
let sb = get_packed_b32(src) as i32;
let sa = get_packed_a32(src) as i32;
let dr = get_packed_r32(dst) as i32;
let dg = get_packed_g32(dst) as i32;
let db = get_packed_b32(dst) as i32;
let da = get_packed_a32(dst) as i32;
let mut Dr;
let mut Dg;
let mut Db;
if sa != 0 && da != 0 {
Dr = dr * sa;
Dg = dg * sa;
Db = db * sa;
set_sat(&mut Dr, &mut Dg, &mut Db, sat(sr, sg, sb) * da);
set_lum(&mut Dr, &mut Dg, &mut Db, sa * da, lum(dr, dg, db) * sa);
} else {
Dr = 0;
Dg = 0;
Db = 0;
}
pack_argb32(
srcover_byte(sa as u32, da as u32),
blendfunc_nonsep_byte(sr, dr, sa, da, Dr),
blendfunc_nonsep_byte(sg, dg, sa, da, Dg),
blendfunc_nonsep_byte(sb, db, sa, da, Db)
)
}
}
pub struct Color;
impl Blend for Color {
fn blend(src: u32, dst: u32) -> u32 {
let sr = get_packed_r32(src) as i32;
let sg = get_packed_g32(src) as i32;
let sb = get_packed_b32(src) as i32;
let sa = get_packed_a32(src) as i32;
let dr = get_packed_r32(dst) as i32;
let dg = get_packed_g32(dst) as i32;
let db = get_packed_b32(dst) as i32;
let da = get_packed_a32(dst) as i32;
let mut Sr;
let mut Sg;
let mut Sb;
if sa != 0 && da != 0 {
Sr = sr * sa;
Sg = sg * sa;
Sb = sb * sa;
set_lum(&mut Sr, &mut Sg, &mut Sb, sa * da, lum(dr, dg, db) * sa);
} else {
Sr = 0;
Sg = 0;
Sb = 0;
}
pack_argb32(
srcover_byte(sa as u32, da as u32),
blendfunc_nonsep_byte(sr, dr, sa, da, Sr),
blendfunc_nonsep_byte(sg, dg, sa, da, Sg),
blendfunc_nonsep_byte(sb, db, sa, da, Sb)
)
}
}
pub struct Luminosity;
impl Blend for Luminosity {
fn blend(src: u32, dst: u32) -> u32 {
let sr = get_packed_r32(src) as i32;
let sg = get_packed_g32(src) as i32;
let sb = get_packed_b32(src) as i32;
let sa = get_packed_a32(src) as i32;
let dr = get_packed_r32(dst) as i32;
let dg = get_packed_g32(dst) as i32;
let db = get_packed_b32(dst) as i32;
let da = get_packed_a32(dst) as i32;
let mut Dr;
let mut Dg;
let mut Db;
if sa != 0 && da != 0 {
Dr = dr * sa;
Dg = dg * sa;
Db = db * sa;
set_lum(&mut Dr, &mut Dg, &mut Db, sa * da, lum(sr, sg, sb) * da);
} else {
Dr = 0;
Dg = 0;
Db = 0;
}
pack_argb32(
srcover_byte(sa as u32, da as u32),
blendfunc_nonsep_byte(sr, dr, sa, da, Dr),
blendfunc_nonsep_byte(sg, dg, sa, da, Dg),
blendfunc_nonsep_byte(sb, db, sa, da, Db)
)
}
}