* All drawing modes except for B_OP_COPY should respect transparent pixels in

source bitmaps. The destination is preserved now when encountering such
  transparent pixels in the source bitmaps.
* B_OP_ERASE is supposed to replace with the low color whereever a source
  bitmap has a non-transparent pixel.
* The B_OP_MIN and B_OP_MAX drawing modes are supposed to select either the
  source or destination pixel based on their brightness, not combine the two
  pixels' color components into a new pixel. The brightness_for() function is
  taken from ColorConversion.cpp in the interface kit. Probably a simpler
  algorithm would do as well.
* Handle B_TRANSPARENT_MAGIC_* in all cases when drawing bitmaps with non-alpha
  source bitmaps, as all modes except B_OP_COPY are sensitive to transparency.

This should make all drawing modes behave as documented in the BeBook. Except
for B_OP_SELECT, which seems broken under R5, the results compare nicely now.

git-svn-id: file:///srv/svn/repos/haiku/haiku/trunk@26075 a95241bf-73f2-0310-859d-f6bbb57e9c96
This commit is contained in:
Michael Lotz 2008-06-22 02:34:15 +00:00
parent 3d75dfbb4a
commit 61ed28ee13
10 changed files with 116 additions and 72 deletions

View File

@ -1363,12 +1363,13 @@ Painter::_DrawBitmap(agg::rendering_buffer& srcBuffer, color_space format,
}
}
if (format != B_RGB32 || fDrawingMode != B_OP_OVER) {
if (format == B_RGBA32 || fDrawingMode == B_OP_COPY) {
_DrawBitmapGeneric32(srcBuffer, xOffset, yOffset,
xScale, yScale, viewRect);
break;
}
// otherwise fall through to get B_OP_OVER handling for B_RGB32
// otherwise fall through to get proper transparency handling for
// B_RGB32 where a B_TRANSPARENT_MAGIC might be set on pixels
}
default: {
if (format == B_CMAP8 && xScale == 1.0 && yScale == 1.0) {
@ -1396,33 +1397,31 @@ Painter::_DrawBitmap(agg::rendering_buffer& srcBuffer, color_space format,
0, format);
if (err >= B_OK) {
if (fDrawingMode == B_OP_OVER) {
// the original bitmap might have had some of the
// transaparent magic colors set that we now need to
// make transparent in our RGBA32 bitmap again.
switch (format) {
case B_RGB32:
_TransparentMagicToAlpha((uint32 *)srcBuffer.buf(),
srcBuffer.width(), srcBuffer.height(),
srcBuffer.stride(), B_TRANSPARENT_MAGIC_RGBA32,
&temp);
break;
// the original bitmap might have had some of the
// transaparent magic colors set that we now need to
// make transparent in our RGBA32 bitmap again.
switch (format) {
case B_RGB32:
_TransparentMagicToAlpha((uint32 *)srcBuffer.buf(),
srcBuffer.width(), srcBuffer.height(),
srcBuffer.stride(), B_TRANSPARENT_MAGIC_RGBA32,
&temp);
break;
// TODO: not sure if this applies to B_RGBA15 too. It
// should not because B_RGBA15 actually has an alpha
// channel itself and it should have been preserved
// when importing the bitmap. Maybe it applies to
// B_RGB16 though?
case B_RGB15:
_TransparentMagicToAlpha((uint16 *)srcBuffer.buf(),
srcBuffer.width(), srcBuffer.height(),
srcBuffer.stride(), B_TRANSPARENT_MAGIC_RGBA15,
&temp);
break;
// TODO: not sure if this applies to B_RGBA15 too. It
// should not because B_RGBA15 actually has an alpha
// channel itself and it should have been preserved
// when importing the bitmap. Maybe it applies to
// B_RGB16 though?
case B_RGB15:
_TransparentMagicToAlpha((uint16 *)srcBuffer.buf(),
srcBuffer.width(), srcBuffer.height(),
srcBuffer.stride(), B_TRANSPARENT_MAGIC_RGBA15,
&temp);
break;
default:
break;
}
default:
break;
}
agg::rendering_buffer convertedBuffer;

View File

@ -111,5 +111,16 @@ typedef PixelFormat::agg_buffer agg_buffer;
}
static inline
uint8
brightness_for(uint8 red, uint8 green, uint8 blue)
{
// brightness = 0.301 * red + 0.586 * green + 0.113 * blue
// we use for performance reasons:
// brightness = (308 * red + 600 * green + 116 * blue) / 1024
return uint8((308 * red + 600 * green + 116 * blue) / 1024);
}
#endif // DRAWING_MODE_H

View File

@ -135,7 +135,7 @@ blend_color_hspan_add(int x, int y, unsigned len,
if (covers) {
// non-solid opacity
do {
if (*covers) {
if (*covers && colors->a > 0) {
if (*covers == 255) {
ASSIGN_ADD(p, colors->r, colors->g, colors->b);
} else {
@ -150,14 +150,18 @@ blend_color_hspan_add(int x, int y, unsigned len,
// solid full opcacity
if (cover == 255) {
do {
ASSIGN_ADD(p, colors->r, colors->g, colors->b);
if (colors->a > 0) {
ASSIGN_ADD(p, colors->r, colors->g, colors->b);
}
p += 4;
++colors;
} while(--len);
// solid partial opacity
} else if (cover) {
do {
BLEND_ADD(p, colors->r, colors->g, colors->b, cover);
if (colors->a > 0) {
BLEND_ADD(p, colors->r, colors->g, colors->b, cover);
}
p += 4;
++colors;
} while(--len);

View File

@ -134,16 +134,18 @@ blend_color_hspan_erase(int x, int y, unsigned len,
const uint8* covers, uint8 cover,
agg_buffer* buffer, const PatternHandler* pattern)
{
// TODO: compare this with BView
uint8* p = buffer->row_ptr(y) + (x << 2);
rgb_color lowColor = pattern->LowColor();
if (covers) {
// non-solid opacity
do {
if(*covers) {
if(*covers == 255) {
ASSIGN_ERASE(p, colors->r, colors->g, colors->b);
if (*covers && colors->a > 0) {
if (*covers == 255) {
ASSIGN_ERASE(p, lowColor.red, lowColor.green,
lowColor.blue);
} else {
BLEND_ERASE(p, colors->r, colors->g, colors->b, *covers);
BLEND_ERASE(p, lowColor.red, lowColor.green, lowColor.blue,
*covers);
}
}
covers++;
@ -154,14 +156,20 @@ blend_color_hspan_erase(int x, int y, unsigned len,
// solid full opcacity
if (cover == 255) {
do {
ASSIGN_ERASE(p, colors->r, colors->g, colors->b);
if (colors->a > 0) {
ASSIGN_ERASE(p, lowColor.red, lowColor.green,
lowColor.blue);
}
p += 4;
++colors;
} while(--len);
// solid partial opacity
} else if (cover) {
do {
BLEND_ERASE(p, colors->r, colors->g, colors->b, cover);
if (colors->a > 0) {
BLEND_ERASE(p, lowColor.red, lowColor.green, lowColor.blue,
cover);
}
p += 4;
++colors;
} while(--len);

View File

@ -157,8 +157,11 @@ blend_color_hspan_invert(int x, int y, unsigned len,
// solid partial opacity
} else if (cover) {
do {
BLEND_INVERT(p, cover);
if (colors->a > 0) {
BLEND_INVERT(p, cover);
}
p += 4;
++colors;
} while(--len);
}
}

View File

@ -17,10 +17,10 @@
{ \
pixel32 _p; \
_p.data32 = *(uint32*)d; \
uint8 rt = max_c(_p.data8[2], (r)); \
uint8 gt = max_c(_p.data8[1], (g)); \
uint8 bt = max_c(_p.data8[0], (b)); \
BLEND(d, rt, gt, bt, a); \
if (brightness_for((r), (g), (b)) \
> brightness_for(_p.data8[2], _p.data8[1], _p.data8[0])) { \
BLEND(d, (r), (g), (b), a); \
} \
}
// ASSIGN_MAX
@ -28,10 +28,13 @@
{ \
pixel32 _p; \
_p.data32 = *(uint32*)d; \
d[0] = max_c(_p.data8[0], (b)); \
d[1] = max_c(_p.data8[1], (g)); \
d[2] = max_c(_p.data8[2], (r)); \
d[3] = 255; \
if (brightness_for((r), (g), (b)) \
> brightness_for(_p.data8[2], _p.data8[1], _p.data8[0])) { \
d[0] = (b); \
d[1] = (g); \
d[2] = (r); \
d[3] = 255; \
} \
}
@ -135,7 +138,7 @@ blend_color_hspan_max(int x, int y, unsigned len,
if (covers) {
// non-solid opacity
do {
if (*covers) {
if (*covers && colors->a > 0) {
if (*covers == 255) {
ASSIGN_MAX(p, colors->r, colors->g, colors->b);
} else {
@ -150,14 +153,18 @@ blend_color_hspan_max(int x, int y, unsigned len,
// solid full opcacity
if (cover == 255) {
do {
ASSIGN_MAX(p, colors->r, colors->g, colors->b);
if (colors->a > 0) {
ASSIGN_MAX(p, colors->r, colors->g, colors->b);
}
p += 4;
++colors;
} while(--len);
// solid partial opacity
} else if (cover) {
do {
BLEND_MAX(p, colors->r, colors->g, colors->b, cover);
if (colors->a > 0) {
BLEND_MAX(p, colors->r, colors->g, colors->b, cover);
}
p += 4;
++colors;
} while(--len);

View File

@ -11,10 +11,10 @@
{ \
pixel32 _p; \
_p.data32 = *(uint32*)d; \
uint8 rt = min_c(_p.data8[2], (r)); \
uint8 gt = min_c(_p.data8[1], (g)); \
uint8 bt = min_c(_p.data8[0], (b)); \
BLEND(d, rt, gt, bt, a); \
if (brightness_for((r), (g), (b)) \
< brightness_for(_p.data8[2], _p.data8[1], _p.data8[0])) { \
BLEND(d, (r), (g), (b), a); \
} \
}
// ASSIGN_MIN
@ -22,10 +22,13 @@
{ \
pixel32 _p; \
_p.data32 = *(uint32*)d; \
d[0] = min_c(_p.data8[0], (b)); \
d[1] = min_c(_p.data8[1], (g)); \
d[2] = min_c(_p.data8[2], (r)); \
d[3] = 255; \
if (brightness_for((r), (g), (b)) \
< brightness_for(_p.data8[2], _p.data8[1], _p.data8[0])) { \
d[0] = (b); \
d[1] = (g); \
d[2] = (r); \
d[3] = 255; \
} \
}
@ -129,7 +132,7 @@ blend_color_hspan_min(int x, int y, unsigned len,
if (covers) {
// non-solid opacity
do {
if (*covers) {
if (*covers && colors->a > 0) {
if (*covers == 255) {
ASSIGN_MIN(p, colors->r, colors->g, colors->b);
} else {
@ -144,14 +147,18 @@ blend_color_hspan_min(int x, int y, unsigned len,
// solid full opcacity
if (cover == 255) {
do {
ASSIGN_MIN(p, colors->r, colors->g, colors->b);
if (colors->a > 0) {
ASSIGN_MIN(p, colors->r, colors->g, colors->b);
}
p += 4;
++colors;
} while(--len);
// solid partial opacity
} else if (cover) {
do {
BLEND_MIN(p, colors->r, colors->g, colors->b, cover);
if (colors->a > 0) {
BLEND_MIN(p, colors->r, colors->g, colors->b, cover);
}
p += 4;
++colors;
} while(--len);

View File

@ -138,8 +138,7 @@ blend_color_hspan_over(int x, int y, unsigned len,
if (covers) {
// non-solid opacity
do {
// if (*covers) {
if (*covers && (colors->a & 0xff)) {
if (*covers && colors->a > 0) {
if (*covers == 255) {
ASSIGN_OVER(p, colors->r, colors->g, colors->b);
} else {
@ -154,16 +153,18 @@ if (*covers && (colors->a & 0xff)) {
// solid full opcacity
if (cover == 255) {
do {
if (colors->a & 0xff) {
ASSIGN_OVER(p, colors->r, colors->g, colors->b);
}
if (colors->a > 0) {
ASSIGN_OVER(p, colors->r, colors->g, colors->b);
}
p += 4;
++colors;
} while(--len);
// solid partial opacity
} else if (cover) {
do {
BLEND_OVER(p, colors->r, colors->g, colors->b, cover);
if (colors->a > 0) {
BLEND_OVER(p, colors->r, colors->g, colors->b, cover);
}
p += 4;
++colors;
} while(--len);

View File

@ -169,7 +169,7 @@ blend_color_hspan_select(int x, int y, unsigned len,
if (covers) {
// non-solid opacity
do {
if (*covers && compare(p, high, low, &color)) {
if (*covers && colors->a > 0 && compare(p, high, low, &color)) {
if (*covers == 255) {
ASSIGN_SELECT(p, color.red, color.green, color.blue);
} else {
@ -184,7 +184,7 @@ blend_color_hspan_select(int x, int y, unsigned len,
// solid full opcacity
if (cover == 255) {
do {
if (compare(p, high, low, &color)) {
if (colors->a > 0 && compare(p, high, low, &color)) {
ASSIGN_SELECT(p, color.red, color.green, color.blue);
}
p += 4;
@ -193,7 +193,7 @@ blend_color_hspan_select(int x, int y, unsigned len,
// solid partial opacity
} else if (cover) {
do {
if (compare(p, high, low, &color)) {
if (colors->a > 0 && compare(p, high, low, &color)) {
BLEND_SELECT(p, color.red, color.green, color.blue, *covers);
}
p += 4;

View File

@ -137,7 +137,7 @@ blend_color_hspan_subtract(int x, int y, unsigned len,
if (covers) {
// non-solid opacity
do {
if (*covers) {
if (*covers && colors->a > 0) {
if (*covers == 255) {
ASSIGN_SUBTRACT(p, colors->r, colors->g, colors->b);
} else {
@ -152,14 +152,18 @@ blend_color_hspan_subtract(int x, int y, unsigned len,
// solid full opcacity
if (cover == 255) {
do {
ASSIGN_SUBTRACT(p, colors->r, colors->g, colors->b);
if (colors->a > 0) {
ASSIGN_SUBTRACT(p, colors->r, colors->g, colors->b);
}
p += 4;
++colors;
} while(--len);
// solid partial opacity
} else if (cover) {
do {
BLEND_SUBTRACT(p, colors->r, colors->g, colors->b, cover);
if (colors->a > 0) {
BLEND_SUBTRACT(p, colors->r, colors->g, colors->b, cover);
}
p += 4;
++colors;
} while(--len);