* 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
+26 -27
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, _DrawBitmapGeneric32(srcBuffer, xOffset, yOffset,
xScale, yScale, viewRect); xScale, yScale, viewRect);
break; 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: { default: {
if (format == B_CMAP8 && xScale == 1.0 && yScale == 1.0) { 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); 0, format);
if (err >= B_OK) { if (err >= B_OK) {
if (fDrawingMode == B_OP_OVER) { // the original bitmap might have had some of the
// the original bitmap might have had some of the // transaparent magic colors set that we now need to
// transaparent magic colors set that we now need to // make transparent in our RGBA32 bitmap again.
// make transparent in our RGBA32 bitmap again. switch (format) {
switch (format) { case B_RGB32:
case B_RGB32: _TransparentMagicToAlpha((uint32 *)srcBuffer.buf(),
_TransparentMagicToAlpha((uint32 *)srcBuffer.buf(), srcBuffer.width(), srcBuffer.height(),
srcBuffer.width(), srcBuffer.height(), srcBuffer.stride(), B_TRANSPARENT_MAGIC_RGBA32,
srcBuffer.stride(), B_TRANSPARENT_MAGIC_RGBA32, &temp);
&temp); break;
break;
// TODO: not sure if this applies to B_RGBA15 too. It // TODO: not sure if this applies to B_RGBA15 too. It
// should not because B_RGBA15 actually has an alpha // should not because B_RGBA15 actually has an alpha
// channel itself and it should have been preserved // channel itself and it should have been preserved
// when importing the bitmap. Maybe it applies to // when importing the bitmap. Maybe it applies to
// B_RGB16 though? // B_RGB16 though?
case B_RGB15: case B_RGB15:
_TransparentMagicToAlpha((uint16 *)srcBuffer.buf(), _TransparentMagicToAlpha((uint16 *)srcBuffer.buf(),
srcBuffer.width(), srcBuffer.height(), srcBuffer.width(), srcBuffer.height(),
srcBuffer.stride(), B_TRANSPARENT_MAGIC_RGBA15, srcBuffer.stride(), B_TRANSPARENT_MAGIC_RGBA15,
&temp); &temp);
break; break;
default: default:
break; break;
}
} }
agg::rendering_buffer convertedBuffer; agg::rendering_buffer convertedBuffer;
@@ -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 #endif // DRAWING_MODE_H
@@ -135,7 +135,7 @@ blend_color_hspan_add(int x, int y, unsigned len,
if (covers) { if (covers) {
// non-solid opacity // non-solid opacity
do { do {
if (*covers) { if (*covers && colors->a > 0) {
if (*covers == 255) { if (*covers == 255) {
ASSIGN_ADD(p, colors->r, colors->g, colors->b); ASSIGN_ADD(p, colors->r, colors->g, colors->b);
} else { } else {
@@ -150,14 +150,18 @@ blend_color_hspan_add(int x, int y, unsigned len,
// solid full opcacity // solid full opcacity
if (cover == 255) { if (cover == 255) {
do { 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; p += 4;
++colors; ++colors;
} while(--len); } while(--len);
// solid partial opacity // solid partial opacity
} else if (cover) { } else if (cover) {
do { 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; p += 4;
++colors; ++colors;
} while(--len); } while(--len);
@@ -134,16 +134,18 @@ blend_color_hspan_erase(int x, int y, unsigned len,
const uint8* covers, uint8 cover, const uint8* covers, uint8 cover,
agg_buffer* buffer, const PatternHandler* pattern) agg_buffer* buffer, const PatternHandler* pattern)
{ {
// TODO: compare this with BView
uint8* p = buffer->row_ptr(y) + (x << 2); uint8* p = buffer->row_ptr(y) + (x << 2);
rgb_color lowColor = pattern->LowColor();
if (covers) { if (covers) {
// non-solid opacity // non-solid opacity
do { do {
if(*covers) { if (*covers && colors->a > 0) {
if(*covers == 255) { if (*covers == 255) {
ASSIGN_ERASE(p, colors->r, colors->g, colors->b); ASSIGN_ERASE(p, lowColor.red, lowColor.green,
lowColor.blue);
} else { } else {
BLEND_ERASE(p, colors->r, colors->g, colors->b, *covers); BLEND_ERASE(p, lowColor.red, lowColor.green, lowColor.blue,
*covers);
} }
} }
covers++; covers++;
@@ -154,14 +156,20 @@ blend_color_hspan_erase(int x, int y, unsigned len,
// solid full opcacity // solid full opcacity
if (cover == 255) { if (cover == 255) {
do { 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; p += 4;
++colors; ++colors;
} while(--len); } while(--len);
// solid partial opacity // solid partial opacity
} else if (cover) { } else if (cover) {
do { 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; p += 4;
++colors; ++colors;
} while(--len); } while(--len);
@@ -157,8 +157,11 @@ blend_color_hspan_invert(int x, int y, unsigned len,
// solid partial opacity // solid partial opacity
} else if (cover) { } else if (cover) {
do { do {
BLEND_INVERT(p, cover); if (colors->a > 0) {
BLEND_INVERT(p, cover);
}
p += 4; p += 4;
++colors;
} while(--len); } while(--len);
} }
} }
@@ -17,10 +17,10 @@
{ \ { \
pixel32 _p; \ pixel32 _p; \
_p.data32 = *(uint32*)d; \ _p.data32 = *(uint32*)d; \
uint8 rt = max_c(_p.data8[2], (r)); \ if (brightness_for((r), (g), (b)) \
uint8 gt = max_c(_p.data8[1], (g)); \ > brightness_for(_p.data8[2], _p.data8[1], _p.data8[0])) { \
uint8 bt = max_c(_p.data8[0], (b)); \ BLEND(d, (r), (g), (b), a); \
BLEND(d, rt, gt, bt, a); \ } \
} }
// ASSIGN_MAX // ASSIGN_MAX
@@ -28,10 +28,13 @@
{ \ { \
pixel32 _p; \ pixel32 _p; \
_p.data32 = *(uint32*)d; \ _p.data32 = *(uint32*)d; \
d[0] = max_c(_p.data8[0], (b)); \ if (brightness_for((r), (g), (b)) \
d[1] = max_c(_p.data8[1], (g)); \ > brightness_for(_p.data8[2], _p.data8[1], _p.data8[0])) { \
d[2] = max_c(_p.data8[2], (r)); \ d[0] = (b); \
d[3] = 255; \ 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) { if (covers) {
// non-solid opacity // non-solid opacity
do { do {
if (*covers) { if (*covers && colors->a > 0) {
if (*covers == 255) { if (*covers == 255) {
ASSIGN_MAX(p, colors->r, colors->g, colors->b); ASSIGN_MAX(p, colors->r, colors->g, colors->b);
} else { } else {
@@ -150,14 +153,18 @@ blend_color_hspan_max(int x, int y, unsigned len,
// solid full opcacity // solid full opcacity
if (cover == 255) { if (cover == 255) {
do { 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; p += 4;
++colors; ++colors;
} while(--len); } while(--len);
// solid partial opacity // solid partial opacity
} else if (cover) { } else if (cover) {
do { 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; p += 4;
++colors; ++colors;
} while(--len); } while(--len);
@@ -11,10 +11,10 @@
{ \ { \
pixel32 _p; \ pixel32 _p; \
_p.data32 = *(uint32*)d; \ _p.data32 = *(uint32*)d; \
uint8 rt = min_c(_p.data8[2], (r)); \ if (brightness_for((r), (g), (b)) \
uint8 gt = min_c(_p.data8[1], (g)); \ < brightness_for(_p.data8[2], _p.data8[1], _p.data8[0])) { \
uint8 bt = min_c(_p.data8[0], (b)); \ BLEND(d, (r), (g), (b), a); \
BLEND(d, rt, gt, bt, a); \ } \
} }
// ASSIGN_MIN // ASSIGN_MIN
@@ -22,10 +22,13 @@
{ \ { \
pixel32 _p; \ pixel32 _p; \
_p.data32 = *(uint32*)d; \ _p.data32 = *(uint32*)d; \
d[0] = min_c(_p.data8[0], (b)); \ if (brightness_for((r), (g), (b)) \
d[1] = min_c(_p.data8[1], (g)); \ < brightness_for(_p.data8[2], _p.data8[1], _p.data8[0])) { \
d[2] = min_c(_p.data8[2], (r)); \ d[0] = (b); \
d[3] = 255; \ 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) { if (covers) {
// non-solid opacity // non-solid opacity
do { do {
if (*covers) { if (*covers && colors->a > 0) {
if (*covers == 255) { if (*covers == 255) {
ASSIGN_MIN(p, colors->r, colors->g, colors->b); ASSIGN_MIN(p, colors->r, colors->g, colors->b);
} else { } else {
@@ -144,14 +147,18 @@ blend_color_hspan_min(int x, int y, unsigned len,
// solid full opcacity // solid full opcacity
if (cover == 255) { if (cover == 255) {
do { 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; p += 4;
++colors; ++colors;
} while(--len); } while(--len);
// solid partial opacity // solid partial opacity
} else if (cover) { } else if (cover) {
do { 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; p += 4;
++colors; ++colors;
} while(--len); } while(--len);
@@ -138,8 +138,7 @@ blend_color_hspan_over(int x, int y, unsigned len,
if (covers) { if (covers) {
// non-solid opacity // non-solid opacity
do { do {
// if (*covers) { if (*covers && colors->a > 0) {
if (*covers && (colors->a & 0xff)) {
if (*covers == 255) { if (*covers == 255) {
ASSIGN_OVER(p, colors->r, colors->g, colors->b); ASSIGN_OVER(p, colors->r, colors->g, colors->b);
} else { } else {
@@ -154,16 +153,18 @@ if (*covers && (colors->a & 0xff)) {
// solid full opcacity // solid full opcacity
if (cover == 255) { if (cover == 255) {
do { do {
if (colors->a & 0xff) { if (colors->a > 0) {
ASSIGN_OVER(p, colors->r, colors->g, colors->b); ASSIGN_OVER(p, colors->r, colors->g, colors->b);
} }
p += 4; p += 4;
++colors; ++colors;
} while(--len); } while(--len);
// solid partial opacity // solid partial opacity
} else if (cover) { } else if (cover) {
do { 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; p += 4;
++colors; ++colors;
} while(--len); } while(--len);
@@ -169,7 +169,7 @@ blend_color_hspan_select(int x, int y, unsigned len,
if (covers) { if (covers) {
// non-solid opacity // non-solid opacity
do { do {
if (*covers && compare(p, high, low, &color)) { if (*covers && colors->a > 0 && compare(p, high, low, &color)) {
if (*covers == 255) { if (*covers == 255) {
ASSIGN_SELECT(p, color.red, color.green, color.blue); ASSIGN_SELECT(p, color.red, color.green, color.blue);
} else { } else {
@@ -184,7 +184,7 @@ blend_color_hspan_select(int x, int y, unsigned len,
// solid full opcacity // solid full opcacity
if (cover == 255) { if (cover == 255) {
do { 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); ASSIGN_SELECT(p, color.red, color.green, color.blue);
} }
p += 4; p += 4;
@@ -193,7 +193,7 @@ blend_color_hspan_select(int x, int y, unsigned len,
// solid partial opacity // solid partial opacity
} else if (cover) { } else if (cover) {
do { 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); BLEND_SELECT(p, color.red, color.green, color.blue, *covers);
} }
p += 4; p += 4;
@@ -137,7 +137,7 @@ blend_color_hspan_subtract(int x, int y, unsigned len,
if (covers) { if (covers) {
// non-solid opacity // non-solid opacity
do { do {
if (*covers) { if (*covers && colors->a > 0) {
if (*covers == 255) { if (*covers == 255) {
ASSIGN_SUBTRACT(p, colors->r, colors->g, colors->b); ASSIGN_SUBTRACT(p, colors->r, colors->g, colors->b);
} else { } else {
@@ -152,14 +152,18 @@ blend_color_hspan_subtract(int x, int y, unsigned len,
// solid full opcacity // solid full opcacity
if (cover == 255) { if (cover == 255) {
do { 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; p += 4;
++colors; ++colors;
} while(--len); } while(--len);
// solid partial opacity // solid partial opacity
} else if (cover) { } else if (cover) {
do { 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; p += 4;
++colors; ++colors;
} while(--len); } while(--len);