mirror of
https://github.com/processing/processing4.git
synced 2026-06-16 04:26:26 +02:00
Merge pull request #3592 from JakubValtar/bugfix-pimage-blend
Fix Java2D blending issues
This commit is contained in:
@@ -1862,8 +1862,8 @@ public class PImage implements PConstants, Cloneable {
|
||||
loadPixels();
|
||||
if (src == this) {
|
||||
if (intersect(sx, sy, sx2, sy2, dx, dy, dx2, dy2)) {
|
||||
blit_resize(get(sx, sy, sx2 - sx, sy2 - sy),
|
||||
0, 0, sx2 - sx - 1, sy2 - sy - 1,
|
||||
blit_resize(get(sx, sy, sw, sh),
|
||||
0, 0, sw, sh,
|
||||
pixels, pixelWidth, pixelHeight, dx, dy, dx2, dy2, mode);
|
||||
} else {
|
||||
// same as below, except skip the loadPixels() because it'd be redundant
|
||||
@@ -1967,8 +1967,8 @@ public class PImage implements PConstants, Cloneable {
|
||||
destY1 = 0;
|
||||
}
|
||||
|
||||
destW = low(destW, screenW - destX1);
|
||||
destH = low(destH, screenH - destY1);
|
||||
destW = min(destW, screenW - destX1);
|
||||
destH = min(destH, screenH - destY1);
|
||||
|
||||
int destOffset = destY1 * screenW + destX1;
|
||||
srcBuffer = img.pixels;
|
||||
@@ -2416,21 +2416,21 @@ public class PImage implements PConstants, Cloneable {
|
||||
private void filter_new_scanline() {
|
||||
sX = srcXOffset;
|
||||
fracV = srcYOffset & PREC_MAXVAL;
|
||||
ifV = PREC_MAXVAL - fracV;
|
||||
ifV = PREC_MAXVAL - fracV + 1;
|
||||
v1 = (srcYOffset >> PRECISIONB) * iw;
|
||||
v2 = low((srcYOffset >> PRECISIONB) + 1, ih1) * iw;
|
||||
v2 = min((srcYOffset >> PRECISIONB) + 1, ih1) * iw;
|
||||
}
|
||||
|
||||
|
||||
private int filter_bilinear() {
|
||||
fracU = sX & PREC_MAXVAL;
|
||||
ifU = PREC_MAXVAL - fracU;
|
||||
ifU = PREC_MAXVAL - fracU + 1;
|
||||
ul = (ifU * ifV) >> PRECISIONB;
|
||||
ll = (ifU * fracV) >> PRECISIONB;
|
||||
ur = (fracU * ifV) >> PRECISIONB;
|
||||
lr = (fracU * fracV) >> PRECISIONB;
|
||||
ll = ifU - ul;
|
||||
ur = ifV - ul;
|
||||
lr = PREC_MAXVAL + 1 - ul - ll - ur;
|
||||
u1 = (sX >> PRECISIONB);
|
||||
u2 = low(u1 + 1, iw1);
|
||||
u2 = min(u1 + 1, iw1);
|
||||
|
||||
// get color values of the 4 neighbouring texels
|
||||
cUL = srcBuffer[v1 + u1];
|
||||
@@ -2464,333 +2464,479 @@ public class PImage implements PConstants, Cloneable {
|
||||
// internal blending methods
|
||||
|
||||
|
||||
private static int low(int a, int b) {
|
||||
private static int min(int a, int b) {
|
||||
return (a < b) ? a : b;
|
||||
}
|
||||
|
||||
|
||||
private static int high(int a, int b) {
|
||||
private static int max(int a, int b) {
|
||||
return (a > b) ? a : b;
|
||||
}
|
||||
|
||||
// davbol - added peg helper, equiv to constrain(n,0,255)
|
||||
private static int peg(int n) {
|
||||
return (n < 0) ? 0 : ((n > 255) ? 255 : n);
|
||||
}
|
||||
|
||||
private static int mix(int a, int b, int f) {
|
||||
return a + (((b - a) * f) >> 8);
|
||||
}
|
||||
|
||||
|
||||
|
||||
/////////////////////////////////////////////////////////////
|
||||
|
||||
// BLEND MODE IMPLEMENTIONS
|
||||
// BLEND MODE IMPLEMENTATIONS
|
||||
|
||||
/*
|
||||
* Jakub Valtar
|
||||
*
|
||||
* All modes use SRC alpha to interpolate between DST and the result of
|
||||
* the operation:
|
||||
*
|
||||
* R = (1 - SRC_ALPHA) * DST + SRC_ALPHA * <RESULT OF THE OPERATION>
|
||||
*
|
||||
* Comments above each mode only specify the formula of its operation.
|
||||
*
|
||||
* These implementations treat alpha 127 (=255/2) as a perfect 50 % mix.
|
||||
*
|
||||
* One alpha value between 126 and 127 is intentionally left out,
|
||||
* so the step 126 -> 127 is twice as big compared to other steps.
|
||||
* This is because our colors are in 0..255 range, but we divide
|
||||
* by right shifting 8 places (=256) which is much faster than
|
||||
* (correct) float division by 255.0f. The missing value was placed
|
||||
* between 126 and 127, because limits of the range (near 0 and 255) and
|
||||
* the middle value (127) have to blend correctly.
|
||||
*
|
||||
* Below you will often see RED and BLUE channels (RB) manipulated together
|
||||
* and GREEN channel (GN) manipulated separately. It is sometimes possible
|
||||
* because the operation won't use more than 16 bits, so we process the RED
|
||||
* channel in the upper 16 bits and BLUE channel in the lower 16 bits. This
|
||||
* decreases the number of operations per pixel and thus makes things faster.
|
||||
*
|
||||
* Some of the modes are hand tweaked (various +1s etc.) to be more accurate
|
||||
* and to produce correct values in extremes. Below is a sketch you can use
|
||||
* to check any blending function for
|
||||
*
|
||||
* 1) Discrepancies between color channels:
|
||||
* - highlighted by the offending color
|
||||
* 2) Behavior at extremes (set colorCount to 256):
|
||||
* - values of all corners are printed to the console
|
||||
* 3) Rounding errors:
|
||||
* - set colorCount to lower value to better see color bands
|
||||
*
|
||||
|
||||
private static int blend_blend(int a, int b) {
|
||||
int f = (b & ALPHA_MASK) >>> 24;
|
||||
// use powers of 2 in range 2..256
|
||||
// to better see color bands
|
||||
final int colorCount = 256;
|
||||
|
||||
return (low(((a & ALPHA_MASK) >>> 24) + f, 0xff) << 24 |
|
||||
mix(a & RED_MASK, b & RED_MASK, f) & RED_MASK |
|
||||
mix(a & GREEN_MASK, b & GREEN_MASK, f) & GREEN_MASK |
|
||||
mix(a & BLUE_MASK, b & BLUE_MASK, f));
|
||||
final int blockSize = 3;
|
||||
|
||||
void settings() {
|
||||
size(blockSize * 256, blockSize * 256);
|
||||
}
|
||||
|
||||
void setup() { }
|
||||
|
||||
void draw() {
|
||||
noStroke();
|
||||
colorMode(RGB, colorCount-1);
|
||||
int alpha = (mouseX / blockSize) << 24;
|
||||
int r, g, b, r2, g2, b2 = 0;
|
||||
for (int x = 0; x <= 0xFF; x++) {
|
||||
for (int y = 0; y <= 0xFF; y++) {
|
||||
int dst = (x << 16) | (x << 8) | x;
|
||||
int src = (y << 16) | (y << 8) | y | alpha;
|
||||
int result = testFunction(dst, src);
|
||||
r = r2 = (result >> 16 & 0xFF);
|
||||
g = g2 = (result >> 8 & 0xFF);
|
||||
b = b2 = (result >> 0 & 0xFF);
|
||||
if (r != g && r != b) r2 = (128 + r2) % 255;
|
||||
if (g != r && g != b) g2 = (128 + g2) % 255;
|
||||
if (b != r && b != g) b2 = (128 + b2) % 255;
|
||||
fill(r2 % colorCount, g2 % colorCount, b2 % colorCount);
|
||||
rect(x * blockSize, y * blockSize, blockSize, blockSize);
|
||||
}
|
||||
}
|
||||
println(
|
||||
"alpha:", mouseX/blockSize,
|
||||
"TL:", hex(get(0, 0)),
|
||||
"TR:", hex(get(width-1, 0)),
|
||||
"BR:", hex(get(width-1, height-1)),
|
||||
"BL:", hex(get(0, height-1)));
|
||||
}
|
||||
|
||||
int testFunction(int dst, int src) {
|
||||
// your function here
|
||||
return dst;
|
||||
}
|
||||
|
||||
*
|
||||
*
|
||||
*/
|
||||
|
||||
private static final int RB_MASK = 0x00FF00FF;
|
||||
private static final int GN_MASK = 0x0000FF00;
|
||||
|
||||
/**
|
||||
* Blend
|
||||
* O = S
|
||||
*/
|
||||
private static int blend_blend(int dst, int src) {
|
||||
int a = src >>> 24;
|
||||
|
||||
int s_a = a + (a >= 0x7F ? 1 : 0);
|
||||
int d_a = 0x100 - s_a;
|
||||
|
||||
return min((dst >>> 24) + a, 0xFF) << 24 |
|
||||
((dst & RB_MASK) * d_a + (src & RB_MASK) * s_a) >>> 8 & RB_MASK |
|
||||
((dst & GN_MASK) * d_a + (src & GN_MASK) * s_a) >>> 8 & GN_MASK;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* additive blend with clipping
|
||||
* Add
|
||||
* O = MIN(D + S, 1)
|
||||
*/
|
||||
private static int blend_add_pin(int a, int b) {
|
||||
int f = (b & ALPHA_MASK) >>> 24;
|
||||
private static int blend_add_pin(int dst, int src) {
|
||||
int a = src >>> 24;
|
||||
|
||||
return (low(((a & ALPHA_MASK) >>> 24) + f, 0xff) << 24 |
|
||||
low(((a & RED_MASK) +
|
||||
((b & RED_MASK) >> 8) * f), RED_MASK) & RED_MASK |
|
||||
low(((a & GREEN_MASK) +
|
||||
((b & GREEN_MASK) >> 8) * f), GREEN_MASK) & GREEN_MASK |
|
||||
low((a & BLUE_MASK) +
|
||||
(((b & BLUE_MASK) * f) >> 8), BLUE_MASK));
|
||||
int s_a = a + (a >= 0x7F ? 1 : 0);
|
||||
|
||||
int rb = (dst & RB_MASK) + ((src & RB_MASK) * s_a >>> 8 & RB_MASK);
|
||||
int gn = (dst & GN_MASK) + ((src & GN_MASK) * s_a >>> 8);
|
||||
|
||||
return min((dst >>> 24) + a, 0xFF) << 24 |
|
||||
min(rb & 0xFFFF0000, RED_MASK) |
|
||||
min(gn & 0x00FFFF00, GREEN_MASK) |
|
||||
min(rb & 0x0000FFFF, BLUE_MASK);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* subtractive blend with clipping
|
||||
* Subtract
|
||||
* O = MAX(0, D - S)
|
||||
*/
|
||||
private static int blend_sub_pin(int a, int b) {
|
||||
int f = (b & ALPHA_MASK) >>> 24;
|
||||
private static int blend_sub_pin(int dst, int src) {
|
||||
int a = src >>> 24;
|
||||
|
||||
return (low(((a & ALPHA_MASK) >>> 24) + f, 0xff) << 24 |
|
||||
high(((a & RED_MASK) - ((b & RED_MASK) >> 8) * f),
|
||||
GREEN_MASK) & RED_MASK |
|
||||
high(((a & GREEN_MASK) - ((b & GREEN_MASK) >> 8) * f),
|
||||
BLUE_MASK) & GREEN_MASK |
|
||||
high((a & BLUE_MASK) - (((b & BLUE_MASK) * f) >> 8), 0));
|
||||
int s_a = a + (a >= 0x7F ? 1 : 0);
|
||||
|
||||
int rb = ((src & RB_MASK) * s_a >>> 8);
|
||||
int gn = ((src & GREEN_MASK) * s_a >>> 8);
|
||||
|
||||
return min((dst >>> 24) + a, 0xFF) << 24 |
|
||||
max((dst & RED_MASK) - (rb & RED_MASK), 0) |
|
||||
max((dst & GREEN_MASK) - (gn & GREEN_MASK), 0) |
|
||||
max((dst & BLUE_MASK) - (rb & BLUE_MASK), 0);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* only returns the blended lightest colour
|
||||
* Lightest
|
||||
* O = MAX(D, S)
|
||||
*/
|
||||
private static int blend_lightest(int a, int b) {
|
||||
int f = (b & ALPHA_MASK) >>> 24;
|
||||
private static int blend_lightest(int dst, int src) {
|
||||
int a = src >>> 24;
|
||||
|
||||
return (low(((a & ALPHA_MASK) >>> 24) + f, 0xff) << 24 |
|
||||
high(a & RED_MASK, ((b & RED_MASK) >> 8) * f) & RED_MASK |
|
||||
high(a & GREEN_MASK, ((b & GREEN_MASK) >> 8) * f) & GREEN_MASK |
|
||||
high(a & BLUE_MASK, ((b & BLUE_MASK) * f) >> 8));
|
||||
int s_a = a + (a >= 0x7F ? 1 : 0);
|
||||
int d_a = 0x100 - s_a;
|
||||
|
||||
int rb = max(src & RED_MASK, dst & RED_MASK) |
|
||||
max(src & BLUE_MASK, dst & BLUE_MASK);
|
||||
int gn = max(src & GREEN_MASK, dst & GREEN_MASK);
|
||||
|
||||
return min((dst >>> 24) + a, 0xFF) << 24 |
|
||||
((dst & RB_MASK) * d_a + rb * s_a) >>> 8 & RB_MASK |
|
||||
((dst & GN_MASK) * d_a + gn * s_a) >>> 8 & GN_MASK;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* only returns the blended darkest colour
|
||||
* Darkest
|
||||
* O = MIN(D, S)
|
||||
*/
|
||||
private static int blend_darkest(int a, int b) {
|
||||
int f = (b & ALPHA_MASK) >>> 24;
|
||||
private static int blend_darkest(int dst, int src) {
|
||||
int a = src >>> 24;
|
||||
|
||||
return (low(((a & ALPHA_MASK) >>> 24) + f, 0xff) << 24 |
|
||||
mix(a & RED_MASK,
|
||||
low(a & RED_MASK,
|
||||
((b & RED_MASK) >> 8) * f), f) & RED_MASK |
|
||||
mix(a & GREEN_MASK,
|
||||
low(a & GREEN_MASK,
|
||||
((b & GREEN_MASK) >> 8) * f), f) & GREEN_MASK |
|
||||
mix(a & BLUE_MASK,
|
||||
low(a & BLUE_MASK,
|
||||
((b & BLUE_MASK) * f) >> 8), f));
|
||||
int s_a = a + (a >= 0x7F ? 1 : 0);
|
||||
int d_a = 0x100 - s_a;
|
||||
|
||||
int rb = min(src & RED_MASK, dst & RED_MASK) |
|
||||
min(src & BLUE_MASK, dst & BLUE_MASK);
|
||||
int gn = min(src & GREEN_MASK, dst & GREEN_MASK);
|
||||
|
||||
return min((dst >>> 24) + a, 0xFF) << 24 |
|
||||
((dst & RB_MASK) * d_a + rb * s_a) >>> 8 & RB_MASK |
|
||||
((dst & GN_MASK) * d_a + gn * s_a) >>> 8 & GN_MASK;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* returns the absolute value of the difference of the input colors
|
||||
* C = |A - B|
|
||||
* Difference
|
||||
* O = ABS(D - S)
|
||||
*/
|
||||
private static int blend_difference(int a, int b) {
|
||||
// setup (this portion will always be the same)
|
||||
int f = (b & ALPHA_MASK) >>> 24;
|
||||
int ar = (a & RED_MASK) >> 16;
|
||||
int ag = (a & GREEN_MASK) >> 8;
|
||||
int ab = (a & BLUE_MASK);
|
||||
int br = (b & RED_MASK) >> 16;
|
||||
int bg = (b & GREEN_MASK) >> 8;
|
||||
int bb = (b & BLUE_MASK);
|
||||
// formula:
|
||||
int cr = (ar > br) ? (ar-br) : (br-ar);
|
||||
int cg = (ag > bg) ? (ag-bg) : (bg-ag);
|
||||
int cb = (ab > bb) ? (ab-bb) : (bb-ab);
|
||||
// alpha blend (this portion will always be the same)
|
||||
return (low(((a & ALPHA_MASK) >>> 24) + f, 0xff) << 24 |
|
||||
(peg(ar + (((cr - ar) * f) >> 8)) << 16) |
|
||||
(peg(ag + (((cg - ag) * f) >> 8)) << 8) |
|
||||
(peg(ab + (((cb - ab) * f) >> 8)) ) );
|
||||
private static int blend_difference(int dst, int src) {
|
||||
int a = src >>> 24;
|
||||
|
||||
int s_a = a + (a >= 0x7F ? 1 : 0);
|
||||
int d_a = 0x100 - s_a;
|
||||
|
||||
int r = (dst & RED_MASK) - (src & RED_MASK);
|
||||
int b = (dst & BLUE_MASK) - (src & BLUE_MASK);
|
||||
int g = (dst & GREEN_MASK) - (src & GREEN_MASK);
|
||||
|
||||
int rb = (r < 0 ? -r : r) |
|
||||
(b < 0 ? -b : b);
|
||||
int gn = (g < 0 ? -g : g);
|
||||
|
||||
return min((dst >>> 24) + a, 0xFF) << 24 |
|
||||
((dst & RB_MASK) * d_a + rb * s_a) >>> 8 & RB_MASK |
|
||||
((dst & GN_MASK) * d_a + gn * s_a) >>> 8 & GN_MASK;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Cousin of difference, algorithm used here is based on a Lingo version
|
||||
* found here: http://www.mediamacros.com/item/item-1006687616/
|
||||
* (Not yet verified to be correct).
|
||||
* Exclusion
|
||||
* O = (1 - S)D + S(1 - D)
|
||||
* O = D + S - 2DS
|
||||
*/
|
||||
private static int blend_exclusion(int a, int b) {
|
||||
// setup (this portion will always be the same)
|
||||
int f = (b & ALPHA_MASK) >>> 24;
|
||||
int ar = (a & RED_MASK) >> 16;
|
||||
int ag = (a & GREEN_MASK) >> 8;
|
||||
int ab = (a & BLUE_MASK);
|
||||
int br = (b & RED_MASK) >> 16;
|
||||
int bg = (b & GREEN_MASK) >> 8;
|
||||
int bb = (b & BLUE_MASK);
|
||||
// formula:
|
||||
int cr = ar + br - ((ar * br) >> 7);
|
||||
int cg = ag + bg - ((ag * bg) >> 7);
|
||||
int cb = ab + bb - ((ab * bb) >> 7);
|
||||
// alpha blend (this portion will always be the same)
|
||||
return (low(((a & ALPHA_MASK) >>> 24) + f, 0xff) << 24 |
|
||||
(peg(ar + (((cr - ar) * f) >> 8)) << 16) |
|
||||
(peg(ag + (((cg - ag) * f) >> 8)) << 8) |
|
||||
(peg(ab + (((cb - ab) * f) >> 8)) ) );
|
||||
private static int blend_exclusion(int dst, int src) {
|
||||
int a = src >>> 24;
|
||||
|
||||
int s_a = a + (a >= 0x7F ? 1 : 0);
|
||||
int d_a = 0x100 - s_a;
|
||||
|
||||
int d_rb = dst & RB_MASK;
|
||||
int d_gn = dst & GN_MASK;
|
||||
|
||||
int s_gn = src & GN_MASK;
|
||||
|
||||
int f_r = (dst & RED_MASK) >> 16;
|
||||
int f_b = (dst & BLUE_MASK);
|
||||
|
||||
int rb_sub =
|
||||
((src & RED_MASK) * (f_r + (f_r >= 0x7F ? 1 : 0)) |
|
||||
(src & BLUE_MASK) * (f_b + (f_b >= 0x7F ? 1 : 0)))
|
||||
>>> 7 & 0x01FF01FF;
|
||||
int gn_sub = s_gn * (d_gn + (d_gn >= 0x7F00 ? 0x100 : 0))
|
||||
>>> 15 & 0x0001FF00;
|
||||
|
||||
return min((dst >>> 24) + a, 0xFF) << 24 |
|
||||
(d_rb * d_a + (d_rb + (src & RB_MASK) - rb_sub) * s_a) >>> 8 & RB_MASK |
|
||||
(d_gn * d_a + (d_gn + s_gn - gn_sub) * s_a) >>> 8 & GN_MASK;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Multiply
|
||||
* O = DS
|
||||
*/
|
||||
private static int blend_multiply(int dst, int src) {
|
||||
int a = src >>> 24;
|
||||
|
||||
int s_a = a + (a >= 0x7F ? 1 : 0);
|
||||
int d_a = 0x100 - s_a;
|
||||
|
||||
int d_gn = dst & GN_MASK;
|
||||
|
||||
int f_r = (dst & RED_MASK) >> 16;
|
||||
int f_b = (dst & BLUE_MASK);
|
||||
|
||||
int rb =
|
||||
((src & RED_MASK) * (f_r + 1) |
|
||||
(src & BLUE_MASK) * (f_b + 1))
|
||||
>>> 8 & RB_MASK;
|
||||
int gn =
|
||||
(src & GREEN_MASK) * (d_gn + 0x100)
|
||||
>>> 16 & GN_MASK;
|
||||
|
||||
return min((dst >>> 24) + a, 0xFF) << 24 |
|
||||
((dst & RB_MASK) * d_a + rb * s_a) >>> 8 & RB_MASK |
|
||||
(d_gn * d_a + gn * s_a) >>> 8 & GN_MASK;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* returns the product of the input colors
|
||||
* C = A * B
|
||||
* Screen
|
||||
* O = 1 - (1 - D)(1 - S)
|
||||
* O = D + S - DS
|
||||
*/
|
||||
private static int blend_multiply(int a, int b) {
|
||||
// setup (this portion will always be the same)
|
||||
int f = (b & ALPHA_MASK) >>> 24;
|
||||
int ar = (a & RED_MASK) >> 16;
|
||||
int ag = (a & GREEN_MASK) >> 8;
|
||||
int ab = (a & BLUE_MASK);
|
||||
int br = (b & RED_MASK) >> 16;
|
||||
int bg = (b & GREEN_MASK) >> 8;
|
||||
int bb = (b & BLUE_MASK);
|
||||
// formula:
|
||||
int cr = (ar * br) >> 8;
|
||||
int cg = (ag * bg) >> 8;
|
||||
int cb = (ab * bb) >> 8;
|
||||
// alpha blend (this portion will always be the same)
|
||||
return (low(((a & ALPHA_MASK) >>> 24) + f, 0xff) << 24 |
|
||||
(peg(ar + (((cr - ar) * f) >> 8)) << 16) |
|
||||
(peg(ag + (((cg - ag) * f) >> 8)) << 8) |
|
||||
(peg(ab + (((cb - ab) * f) >> 8)) ) );
|
||||
private static int blend_screen(int dst, int src) {
|
||||
int a = src >>> 24;
|
||||
|
||||
int s_a = a + (a >= 0x7F ? 1 : 0);
|
||||
int d_a = 0x100 - s_a;
|
||||
|
||||
int d_rb = dst & RB_MASK;
|
||||
int d_gn = dst & GN_MASK;
|
||||
|
||||
int s_gn = src & GN_MASK;
|
||||
|
||||
int f_r = (dst & RED_MASK) >> 16;
|
||||
int f_b = (dst & BLUE_MASK);
|
||||
|
||||
int rb_sub =
|
||||
((src & RED_MASK) * (f_r + 1) |
|
||||
(src & BLUE_MASK) * (f_b + 1))
|
||||
>>> 8 & RB_MASK;
|
||||
int gn_sub = s_gn * (d_gn + 0x100)
|
||||
>>> 16 & GN_MASK;
|
||||
|
||||
return min((dst >>> 24) + a, 0xFF) << 24 |
|
||||
(d_rb * d_a + (d_rb + (src & RB_MASK) - rb_sub) * s_a) >>> 8 & RB_MASK |
|
||||
(d_gn * d_a + (d_gn + s_gn - gn_sub) * s_a) >>> 8 & GN_MASK;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* returns the inverse of the product of the inverses of the input colors
|
||||
* (the inverse of multiply). C = 1 - (1-A) * (1-B)
|
||||
* Overlay
|
||||
* O = 2 * MULTIPLY(D, S) = 2DS for D < 0.5
|
||||
* O = 2 * SCREEN(D, S) - 1 = 2(S + D - DS) - 1 otherwise
|
||||
*/
|
||||
private static int blend_screen(int a, int b) {
|
||||
// setup (this portion will always be the same)
|
||||
int f = (b & ALPHA_MASK) >>> 24;
|
||||
int ar = (a & RED_MASK) >> 16;
|
||||
int ag = (a & GREEN_MASK) >> 8;
|
||||
int ab = (a & BLUE_MASK);
|
||||
int br = (b & RED_MASK) >> 16;
|
||||
int bg = (b & GREEN_MASK) >> 8;
|
||||
int bb = (b & BLUE_MASK);
|
||||
// formula:
|
||||
int cr = 255 - (((255 - ar) * (255 - br)) >> 8);
|
||||
int cg = 255 - (((255 - ag) * (255 - bg)) >> 8);
|
||||
int cb = 255 - (((255 - ab) * (255 - bb)) >> 8);
|
||||
// alpha blend (this portion will always be the same)
|
||||
return (low(((a & ALPHA_MASK) >>> 24) + f, 0xff) << 24 |
|
||||
(peg(ar + (((cr - ar) * f) >> 8)) << 16) |
|
||||
(peg(ag + (((cg - ag) * f) >> 8)) << 8) |
|
||||
(peg(ab + (((cb - ab) * f) >> 8)) ) );
|
||||
private static int blend_overlay(int dst, int src) {
|
||||
int a = src >>> 24;
|
||||
|
||||
int s_a = a + (a >= 0x7F ? 1 : 0);
|
||||
int d_a = 0x100 - s_a;
|
||||
|
||||
int d_r = dst & RED_MASK;
|
||||
int d_g = dst & GREEN_MASK;
|
||||
int d_b = dst & BLUE_MASK;
|
||||
|
||||
int s_r = src & RED_MASK;
|
||||
int s_g = src & GREEN_MASK;
|
||||
int s_b = src & BLUE_MASK;
|
||||
|
||||
int r = (d_r < 0x800000) ?
|
||||
d_r * ((s_r >>> 16) + 1) >>> 7 :
|
||||
0xFF0000 - ((0x100 - (s_r >>> 16)) * (RED_MASK - d_r) >>> 7);
|
||||
int g = (d_g < 0x8000) ?
|
||||
d_g * (s_g + 0x100) >>> 15 :
|
||||
(0xFF00 - ((0x10000 - s_g) * (GREEN_MASK - d_g) >>> 15));
|
||||
int b = (d_b < 0x80) ?
|
||||
d_b * (s_b + 1) >>> 7 :
|
||||
(0xFF00 - ((0x100 - s_b) * (BLUE_MASK - d_b) << 1)) >>> 8;
|
||||
|
||||
return min((dst >>> 24) + a, 0xFF) << 24 |
|
||||
((dst & RB_MASK) * d_a + ((r | b) & RB_MASK) * s_a) >>> 8 & RB_MASK |
|
||||
((dst & GN_MASK) * d_a + (g & GN_MASK) * s_a) >>> 8 & GN_MASK;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* returns either multiply or screen for darker or lighter values of A
|
||||
* (the inverse of hard light)
|
||||
* C =
|
||||
* A < 0.5 : 2 * A * B
|
||||
* A >=0.5 : 1 - (2 * (255-A) * (255-B))
|
||||
* Hard Light
|
||||
* O = OVERLAY(S, D)
|
||||
*
|
||||
* O = 2 * MULTIPLY(D, S) = 2DS for S < 0.5
|
||||
* O = 2 * SCREEN(D, S) - 1 = 2(S + D - DS) - 1 otherwise
|
||||
*/
|
||||
private static int blend_overlay(int a, int b) {
|
||||
// setup (this portion will always be the same)
|
||||
int f = (b & ALPHA_MASK) >>> 24;
|
||||
int ar = (a & RED_MASK) >> 16;
|
||||
int ag = (a & GREEN_MASK) >> 8;
|
||||
int ab = (a & BLUE_MASK);
|
||||
int br = (b & RED_MASK) >> 16;
|
||||
int bg = (b & GREEN_MASK) >> 8;
|
||||
int bb = (b & BLUE_MASK);
|
||||
// formula:
|
||||
int cr = (ar < 128) ? ((ar*br)>>7) : (255-(((255-ar)*(255-br))>>7));
|
||||
int cg = (ag < 128) ? ((ag*bg)>>7) : (255-(((255-ag)*(255-bg))>>7));
|
||||
int cb = (ab < 128) ? ((ab*bb)>>7) : (255-(((255-ab)*(255-bb))>>7));
|
||||
// alpha blend (this portion will always be the same)
|
||||
return (low(((a & ALPHA_MASK) >>> 24) + f, 0xff) << 24 |
|
||||
(peg(ar + (((cr - ar) * f) >> 8)) << 16) |
|
||||
(peg(ag + (((cg - ag) * f) >> 8)) << 8) |
|
||||
(peg(ab + (((cb - ab) * f) >> 8)) ) );
|
||||
private static int blend_hard_light(int dst, int src) {
|
||||
int a = src >>> 24;
|
||||
|
||||
int s_a = a + (a >= 0x7F ? 1 : 0);
|
||||
int d_a = 0x100 - s_a;
|
||||
|
||||
int d_r = dst & RED_MASK;
|
||||
int d_g = dst & GREEN_MASK;
|
||||
int d_b = dst & BLUE_MASK;
|
||||
|
||||
int s_r = src & RED_MASK;
|
||||
int s_g = src & GREEN_MASK;
|
||||
int s_b = src & BLUE_MASK;
|
||||
|
||||
int r = (s_r < 0x800000) ?
|
||||
s_r * ((d_r >>> 16) + 1) >>> 7 :
|
||||
0xFF0000 - ((0x100 - (d_r >>> 16)) * (RED_MASK - s_r) >>> 7);
|
||||
int g = (s_g < 0x8000) ?
|
||||
s_g * (d_g + 0x100) >>> 15 :
|
||||
(0xFF00 - ((0x10000 - d_g) * (GREEN_MASK - s_g) >>> 15));
|
||||
int b = (s_b < 0x80) ?
|
||||
s_b * (d_b + 1) >>> 7 :
|
||||
(0xFF00 - ((0x100 - d_b) * (BLUE_MASK - s_b) << 1)) >>> 8;
|
||||
|
||||
return min((dst >>> 24) + a, 0xFF) << 24 |
|
||||
((dst & RB_MASK) * d_a + ((r | b) & RB_MASK) * s_a) >>> 8 & RB_MASK |
|
||||
((dst & GN_MASK) * d_a + (g & GN_MASK) * s_a) >>> 8 & GN_MASK;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* returns either multiply or screen for darker or lighter values of B
|
||||
* (the inverse of overlay)
|
||||
* C =
|
||||
* B < 0.5 : 2 * A * B
|
||||
* B >=0.5 : 1 - (2 * (255-A) * (255-B))
|
||||
* Soft Light (Pegtop)
|
||||
* O = (1 - D) * MULTIPLY(D, S) + D * SCREEN(D, S)
|
||||
* O = (1 - D) * DS + D * (1 - (1 - D)(1 - S))
|
||||
* O = 2DS + DD - 2DDS
|
||||
*/
|
||||
private static int blend_hard_light(int a, int b) {
|
||||
// setup (this portion will always be the same)
|
||||
int f = (b & ALPHA_MASK) >>> 24;
|
||||
int ar = (a & RED_MASK) >> 16;
|
||||
int ag = (a & GREEN_MASK) >> 8;
|
||||
int ab = (a & BLUE_MASK);
|
||||
int br = (b & RED_MASK) >> 16;
|
||||
int bg = (b & GREEN_MASK) >> 8;
|
||||
int bb = (b & BLUE_MASK);
|
||||
// formula:
|
||||
int cr = (br < 128) ? ((ar*br)>>7) : (255-(((255-ar)*(255-br))>>7));
|
||||
int cg = (bg < 128) ? ((ag*bg)>>7) : (255-(((255-ag)*(255-bg))>>7));
|
||||
int cb = (bb < 128) ? ((ab*bb)>>7) : (255-(((255-ab)*(255-bb))>>7));
|
||||
// alpha blend (this portion will always be the same)
|
||||
return (low(((a & ALPHA_MASK) >>> 24) + f, 0xff) << 24 |
|
||||
(peg(ar + (((cr - ar) * f) >> 8)) << 16) |
|
||||
(peg(ag + (((cg - ag) * f) >> 8)) << 8) |
|
||||
(peg(ab + (((cb - ab) * f) >> 8)) ) );
|
||||
private static int blend_soft_light(int dst, int src) {
|
||||
int a = src >>> 24;
|
||||
|
||||
int s_a = a + (a >= 0x7F ? 1 : 0);
|
||||
int d_a = 0x100 - s_a;
|
||||
|
||||
int d_r = dst & RED_MASK;
|
||||
int d_g = dst & GREEN_MASK;
|
||||
int d_b = dst & BLUE_MASK;
|
||||
|
||||
int s_r1 = src & RED_MASK >> 16;
|
||||
int s_g1 = src & GREEN_MASK >> 8;
|
||||
int s_b1 = src & BLUE_MASK;
|
||||
|
||||
int d_r1 = (d_r >> 16) + (s_r1 < 7F ? 1 : 0);
|
||||
int d_g1 = (d_g >> 8) + (s_g1 < 7F ? 1 : 0);
|
||||
int d_b1 = d_b + (s_b1 < 7F ? 1 : 0);
|
||||
|
||||
int r = (s_r1 * d_r >> 7) + 0xFF * d_r1 * (d_r1 + 1) -
|
||||
((s_r1 * d_r1 * d_r1) << 1) & RED_MASK;
|
||||
int g = (s_g1 * d_g << 1) + 0xFF * d_g1 * (d_g1 + 1) -
|
||||
((s_g1 * d_g1 * d_g1) << 1) >>> 8 & GREEN_MASK;
|
||||
int b = (s_b1 * d_b << 9) + 0xFF * d_b1 * (d_b1 + 1) -
|
||||
((s_b1 * d_b1 * d_b1) << 1) >>> 16;
|
||||
|
||||
return min((dst >>> 24) + a, 0xFF) << 24 |
|
||||
((dst & RB_MASK) * d_a + (r | b) * s_a) >>> 8 & RB_MASK |
|
||||
((dst & GN_MASK) * d_a + g * s_a) >>> 8 & GN_MASK;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* returns the inverse multiply plus screen, which simplifies to
|
||||
* C = 2AB + A^2 - 2A^2B
|
||||
* Dodge
|
||||
* O = D / (1 - S)
|
||||
*/
|
||||
private static int blend_soft_light(int a, int b) {
|
||||
// setup (this portion will always be the same)
|
||||
int f = (b & ALPHA_MASK) >>> 24;
|
||||
int ar = (a & RED_MASK) >> 16;
|
||||
int ag = (a & GREEN_MASK) >> 8;
|
||||
int ab = (a & BLUE_MASK);
|
||||
int br = (b & RED_MASK) >> 16;
|
||||
int bg = (b & GREEN_MASK) >> 8;
|
||||
int bb = (b & BLUE_MASK);
|
||||
// formula:
|
||||
int cr = ((ar*br)>>7) + ((ar*ar)>>8) - ((ar*ar*br)>>15);
|
||||
int cg = ((ag*bg)>>7) + ((ag*ag)>>8) - ((ag*ag*bg)>>15);
|
||||
int cb = ((ab*bb)>>7) + ((ab*ab)>>8) - ((ab*ab*bb)>>15);
|
||||
// alpha blend (this portion will always be the same)
|
||||
return (low(((a & ALPHA_MASK) >>> 24) + f, 0xff) << 24 |
|
||||
(peg(ar + (((cr - ar) * f) >> 8)) << 16) |
|
||||
(peg(ag + (((cg - ag) * f) >> 8)) << 8) |
|
||||
(peg(ab + (((cb - ab) * f) >> 8)) ) );
|
||||
private static int blend_dodge(int dst, int src) {
|
||||
int a = src >>> 24;
|
||||
|
||||
int s_a = a + (a >= 0x7F ? 1 : 0);
|
||||
int d_a = 0x100 - s_a;
|
||||
|
||||
int r = (dst & RED_MASK) / (256 - ((src & RED_MASK) >> 16));
|
||||
int g = ((dst & GREEN_MASK) << 8) / (256 - ((src & GREEN_MASK) >> 8));
|
||||
int b = ((dst & BLUE_MASK) << 8) / (256 - (src & BLUE_MASK));
|
||||
|
||||
int rb =
|
||||
(r > 0xFF00 ? 0xFF0000 : ((r << 8) & RED_MASK)) |
|
||||
(b > 0x00FF ? 0x0000FF : b);
|
||||
int gn =
|
||||
(g > 0xFF00 ? 0x00FF00 : (g & GREEN_MASK));
|
||||
|
||||
return min((dst >>> 24) + a, 0xFF) << 24 |
|
||||
((dst & RB_MASK) * d_a + rb * s_a) >>> 8 & RB_MASK |
|
||||
((dst & GN_MASK) * d_a + gn * s_a) >>> 8 & GN_MASK;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Returns the first (underlay) color divided by the inverse of
|
||||
* the second (overlay) color. C = A / (255-B)
|
||||
* Burn
|
||||
* O = 1 - (1 - A) / B
|
||||
*/
|
||||
private static int blend_dodge(int a, int b) {
|
||||
// setup (this portion will always be the same)
|
||||
int f = (b & ALPHA_MASK) >>> 24;
|
||||
int ar = (a & RED_MASK) >> 16;
|
||||
int ag = (a & GREEN_MASK) >> 8;
|
||||
int ab = (a & BLUE_MASK);
|
||||
int br = (b & RED_MASK) >> 16;
|
||||
int bg = (b & GREEN_MASK) >> 8;
|
||||
int bb = (b & BLUE_MASK);
|
||||
// formula:
|
||||
int cr = (br==255) ? 255 : peg((ar << 8) / (255 - br)); // division requires pre-peg()-ing
|
||||
int cg = (bg==255) ? 255 : peg((ag << 8) / (255 - bg)); // "
|
||||
int cb = (bb==255) ? 255 : peg((ab << 8) / (255 - bb)); // "
|
||||
// alpha blend (this portion will always be the same)
|
||||
return (low(((a & ALPHA_MASK) >>> 24) + f, 0xff) << 24 |
|
||||
(peg(ar + (((cr - ar) * f) >> 8)) << 16) |
|
||||
(peg(ag + (((cg - ag) * f) >> 8)) << 8) |
|
||||
(peg(ab + (((cb - ab) * f) >> 8)) ) );
|
||||
}
|
||||
private static int blend_burn(int dst, int src) {
|
||||
int a = src >>> 24;
|
||||
|
||||
int s_a = a + (a >= 0x7F ? 1 : 0);
|
||||
int d_a = 0x100 - s_a;
|
||||
|
||||
/**
|
||||
* returns the inverse of the inverse of the first (underlay) color
|
||||
* divided by the second (overlay) color. C = 255 - (255-A) / B
|
||||
*/
|
||||
private static int blend_burn(int a, int b) {
|
||||
// setup (this portion will always be the same)
|
||||
int f = (b & ALPHA_MASK) >>> 24;
|
||||
int ar = (a & RED_MASK) >> 16;
|
||||
int ag = (a & GREEN_MASK) >> 8;
|
||||
int ab = (a & BLUE_MASK);
|
||||
int br = (b & RED_MASK) >> 16;
|
||||
int bg = (b & GREEN_MASK) >> 8;
|
||||
int bb = (b & BLUE_MASK);
|
||||
// formula:
|
||||
int cr = (br==0) ? 0 : 255 - peg(((255 - ar) << 8) / br); // division requires pre-peg()-ing
|
||||
int cg = (bg==0) ? 0 : 255 - peg(((255 - ag) << 8) / bg); // "
|
||||
int cb = (bb==0) ? 0 : 255 - peg(((255 - ab) << 8) / bb); // "
|
||||
// alpha blend (this portion will always be the same)
|
||||
return (low(((a & ALPHA_MASK) >>> 24) + f, 0xff) << 24 |
|
||||
(peg(ar + (((cr - ar) * f) >> 8)) << 16) |
|
||||
(peg(ag + (((cg - ag) * f) >> 8)) << 8) |
|
||||
(peg(ab + (((cb - ab) * f) >> 8)) ) );
|
||||
int r = ((0xFF0000 - (dst & RED_MASK))) / (1 + (src & RED_MASK >> 16));
|
||||
int g = ((0x00FF00 - (dst & GREEN_MASK)) << 8) / (1 + (src & GREEN_MASK >> 8));
|
||||
int b = ((0x0000FF - (dst & BLUE_MASK)) << 8) / (1 + (src & BLUE_MASK));
|
||||
|
||||
int rb = RB_MASK -
|
||||
(r > 0xFF00 ? 0xFF0000 : ((r << 8) & RED_MASK)) -
|
||||
(b > 0x00FF ? 0x0000FF : b);
|
||||
int gn = GN_MASK -
|
||||
(g > 0xFF00 ? 0x00FF00 : (g & GREEN_MASK));
|
||||
|
||||
return min((dst >>> 24) + a, 0xFF) << 24 |
|
||||
((dst & RB_MASK) * d_a + rb * s_a) >>> 8 & RB_MASK |
|
||||
((dst & GN_MASK) * d_a + gn * s_a) >>> 8 & GN_MASK;
|
||||
}
|
||||
|
||||
|
||||
|
||||
Reference in New Issue
Block a user