From 61ed28ee13e6bcf41a9c39c834c1a238881214bd Mon Sep 17 00:00:00 2001 From: Michael Lotz Date: Sun, 22 Jun 2008 02:34:15 +0000 Subject: [PATCH] * 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 --- src/servers/app/drawing/Painter/Painter.cpp | 53 +++++++++---------- .../Painter/drawing_modes/DrawingMode.h | 11 ++++ .../Painter/drawing_modes/DrawingModeAdd.h | 10 ++-- .../Painter/drawing_modes/DrawingModeErase.h | 22 +++++--- .../Painter/drawing_modes/DrawingModeInvert.h | 5 +- .../Painter/drawing_modes/DrawingModeMax.h | 29 ++++++---- .../Painter/drawing_modes/DrawingModeMin.h | 29 ++++++---- .../Painter/drawing_modes/DrawingModeOver.h | 13 ++--- .../Painter/drawing_modes/DrawingModeSelect.h | 6 +-- .../drawing_modes/DrawingModeSubtract.h | 10 ++-- 10 files changed, 116 insertions(+), 72 deletions(-) diff --git a/src/servers/app/drawing/Painter/Painter.cpp b/src/servers/app/drawing/Painter/Painter.cpp index 3c27421547..5a621fcbd5 100644 --- a/src/servers/app/drawing/Painter/Painter.cpp +++ b/src/servers/app/drawing/Painter/Painter.cpp @@ -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; diff --git a/src/servers/app/drawing/Painter/drawing_modes/DrawingMode.h b/src/servers/app/drawing/Painter/drawing_modes/DrawingMode.h index 52a7fd83e6..7821b1a346 100644 --- a/src/servers/app/drawing/Painter/drawing_modes/DrawingMode.h +++ b/src/servers/app/drawing/Painter/drawing_modes/DrawingMode.h @@ -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 diff --git a/src/servers/app/drawing/Painter/drawing_modes/DrawingModeAdd.h b/src/servers/app/drawing/Painter/drawing_modes/DrawingModeAdd.h index 2d73295b01..35e6f876ad 100644 --- a/src/servers/app/drawing/Painter/drawing_modes/DrawingModeAdd.h +++ b/src/servers/app/drawing/Painter/drawing_modes/DrawingModeAdd.h @@ -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); diff --git a/src/servers/app/drawing/Painter/drawing_modes/DrawingModeErase.h b/src/servers/app/drawing/Painter/drawing_modes/DrawingModeErase.h index 80073010f0..735707d740 100644 --- a/src/servers/app/drawing/Painter/drawing_modes/DrawingModeErase.h +++ b/src/servers/app/drawing/Painter/drawing_modes/DrawingModeErase.h @@ -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); diff --git a/src/servers/app/drawing/Painter/drawing_modes/DrawingModeInvert.h b/src/servers/app/drawing/Painter/drawing_modes/DrawingModeInvert.h index 47f99c62cd..5fb8930d65 100644 --- a/src/servers/app/drawing/Painter/drawing_modes/DrawingModeInvert.h +++ b/src/servers/app/drawing/Painter/drawing_modes/DrawingModeInvert.h @@ -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); } } diff --git a/src/servers/app/drawing/Painter/drawing_modes/DrawingModeMax.h b/src/servers/app/drawing/Painter/drawing_modes/DrawingModeMax.h index bdbf2f1aac..48ec95db65 100644 --- a/src/servers/app/drawing/Painter/drawing_modes/DrawingModeMax.h +++ b/src/servers/app/drawing/Painter/drawing_modes/DrawingModeMax.h @@ -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); diff --git a/src/servers/app/drawing/Painter/drawing_modes/DrawingModeMin.h b/src/servers/app/drawing/Painter/drawing_modes/DrawingModeMin.h index 04a7eebb31..57de8116ec 100644 --- a/src/servers/app/drawing/Painter/drawing_modes/DrawingModeMin.h +++ b/src/servers/app/drawing/Painter/drawing_modes/DrawingModeMin.h @@ -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); diff --git a/src/servers/app/drawing/Painter/drawing_modes/DrawingModeOver.h b/src/servers/app/drawing/Painter/drawing_modes/DrawingModeOver.h index fb5658701f..0149beb0ce 100644 --- a/src/servers/app/drawing/Painter/drawing_modes/DrawingModeOver.h +++ b/src/servers/app/drawing/Painter/drawing_modes/DrawingModeOver.h @@ -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); diff --git a/src/servers/app/drawing/Painter/drawing_modes/DrawingModeSelect.h b/src/servers/app/drawing/Painter/drawing_modes/DrawingModeSelect.h index 5484deba8b..fa4cfc5658 100644 --- a/src/servers/app/drawing/Painter/drawing_modes/DrawingModeSelect.h +++ b/src/servers/app/drawing/Painter/drawing_modes/DrawingModeSelect.h @@ -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; diff --git a/src/servers/app/drawing/Painter/drawing_modes/DrawingModeSubtract.h b/src/servers/app/drawing/Painter/drawing_modes/DrawingModeSubtract.h index aed298f65d..97fa5bc7a5 100644 --- a/src/servers/app/drawing/Painter/drawing_modes/DrawingModeSubtract.h +++ b/src/servers/app/drawing/Painter/drawing_modes/DrawingModeSubtract.h @@ -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);