GRAPHICS: Support full alpha when blitting using masks in ManagedSurface

This commit is contained in:
Cameron Cawley 2020-05-03 23:12:40 +01:00 committed by Eugene Sandulenko
parent c5e532f1ad
commit 44e948a283
2 changed files with 58 additions and 53 deletions

View File

@ -361,17 +361,62 @@ void ManagedSurface::transBlitFrom(const ManagedSurface &src, const Common::Rect
srcAlpha, palette, mask, maskOnly);
}
template<typename TSRC, typename TDEST>
void transBlitPixel(TSRC srcVal, TDEST &destVal, const Graphics::PixelFormat &srcFormat, const Graphics::PixelFormat &destFormat,
uint overrideColor, uint srcAlpha, const uint32 *palette) {
if (srcFormat == destFormat && srcAlpha == 0xff) {
// Matching formats, so we can do a straight copy
destVal = overrideColor ? overrideColor : srcVal;
return;
}
// Otherwise we have to manually decode and re-encode each pixel
byte aSrc, rSrc, gSrc, bSrc;
if (srcFormat.bytesPerPixel == 1) {
assert(palette != nullptr); // Catch the cases when palette is missing
// Get the palette color
const uint32 col = palette[srcVal];
rSrc = col & 0xff;
gSrc = (col >> 8) & 0xff;
bSrc = (col >> 16) & 0xff;
aSrc = (col >> 24) & 0xff;
} else {
srcFormat.colorToARGB(srcVal, aSrc, rSrc, gSrc, bSrc);
}
byte rDest, gDest, bDest;
destFormat.colorToRGB(destVal, rDest, gDest, bDest);
if (srcAlpha != 0xff) {
aSrc = aSrc * srcAlpha / 255;
}
if (aSrc == 0) {
// Completely transparent, so skip
return;
} else if (aSrc == 0xff) {
// Completely opaque, so copy RGB values over
rDest = rSrc;
gDest = gSrc;
bDest = bSrc;
} else {
// Partially transparent, so calculate new pixel colors
double alpha = (double)aSrc / 255.0;
rDest = static_cast<byte>((rSrc * alpha) + (rDest * (1.0 - alpha)));
gDest = static_cast<byte>((gSrc * alpha) + (gDest * (1.0 - alpha)));
bDest = static_cast<byte>((bSrc * alpha) + (bDest * (1.0 - alpha)));
}
destVal = destFormat.ARGBToColor(0xff, rDest, gDest, bDest);
}
template<typename TSRC, typename TDEST>
void transBlit(const Surface &src, const Common::Rect &srcRect, Surface &dest, const Common::Rect &destRect,
TSRC transColor, bool flipped, uint overrideColor, uint srcAlpha, const uint32 *palette,
const Surface *mask, bool maskOnly) {
int scaleX = SCALE_THRESHOLD * srcRect.width() / destRect.width();
int scaleY = SCALE_THRESHOLD * srcRect.height() / destRect.height();
const Graphics::PixelFormat &srcFormat = src.format;
const Graphics::PixelFormat &destFormat = dest.format;
byte aSrc, rSrc, gSrc, bSrc;
byte rDest, gDest, bDest;
double alpha;
// Loop through drawing output lines
for (int destY = destRect.top, scaleYCtr = 0; destY < destRect.bottom; ++destY, scaleYCtr += scaleY) {
@ -398,50 +443,10 @@ void transBlit(const Surface &src, const Common::Rect &srcRect, Surface &dest, c
TSRC mskVal = mskLine[flipped ? src.w - scaleXCtr / SCALE_THRESHOLD - 1 : scaleXCtr / SCALE_THRESHOLD];
if (!mskVal)
continue;
}
if (srcFormat == destFormat && srcAlpha == 0xff) {
// Matching formats, so we can do a straight copy
destLine[xCtr] = overrideColor ? overrideColor : srcVal;
transBlitPixel<TSRC, TDEST>(srcVal, destLine[xCtr], src.format, dest.format, overrideColor, mskVal, palette);
} else {
// Otherwise we have to manually decode and re-encode each pixel
if (srcFormat.bytesPerPixel == 1) {
assert(palette != nullptr); // Catch the cases when palette is missing
// Get the palette color
const uint32 col = palette[srcVal];
rSrc = col & 0xff;
gSrc = (col >> 8) & 0xff;
bSrc = (col >> 16) & 0xff;
aSrc = (col >> 24) & 0xff;
} else {
srcFormat.colorToARGB(srcVal, aSrc, rSrc, gSrc, bSrc);
}
destFormat.colorToRGB(destLine[xCtr], rDest, gDest, bDest);
if (srcAlpha != 0xff) {
aSrc = aSrc * srcAlpha / 255;
}
if (aSrc == 0) {
// Completely transparent, so skip
continue;
}
else if (aSrc == 0xff) {
// Completely opaque, so copy RGB values over
rDest = rSrc;
gDest = gSrc;
bDest = bSrc;
}
else {
// Partially transparent, so calculate new pixel colors
alpha = (double)aSrc / 255.0;
rDest = static_cast<byte>((rSrc * alpha) + (rDest * (1.0 - alpha)));
gDest = static_cast<byte>((gSrc * alpha) + (gDest * (1.0 - alpha)));
bDest = static_cast<byte>((bSrc * alpha) + (bDest * (1.0 - alpha)));
}
destLine[xCtr] = destFormat.ARGBToColor(0xff, rDest, gDest, bDest);
transBlitPixel<TSRC, TDEST>(srcVal, destLine[xCtr], src.format, dest.format, overrideColor, srcAlpha, palette);
}
}
}

View File

@ -299,7 +299,7 @@ public:
* Copies another surface into this one ignoring pixels of a designated transparent color
* @param src Source surface
* @param destPos Destination position to draw the surface
* @param mask Mask definition (0-skip, other-copy)
* @param mask Mask definition
*/
void transBlitFrom(const Surface &src, const Common::Point &destPos,
const ManagedSurface &mask);
@ -308,7 +308,7 @@ public:
* Copies another surface into this one ignoring pixels of a designated transparent color
* @param src Source surface
* @param destPos Destination position to draw the surface
* @param mask Mask definition (0-skip, other-copy)
* @param mask Mask definition
*/
void transBlitFrom(const Surface &src, const Common::Point &destPos,
const Surface &mask);
@ -323,8 +323,6 @@ public:
* @param overrideColor Optional color to use instead of non-transparent pixels from
* the source surface
* @param srcAlpha Optional additional transparency applied to src
* @param mask Optional parameter with mask definition (0-skip, other-copy)
* @param maskOnly Optional parameter for using mask over transColor
*/
void transBlitFrom(const Surface &src, const Common::Rect &srcRect, const Common::Point &destPos,
uint transColor = 0, bool flipped = false, uint overrideColor = 0, uint srcAlpha = 0xff);
@ -340,7 +338,7 @@ public:
* @param overrideColor Optional color to use instead of non-transparent pixels from
* the source surface
* @param srcAlpha Optional additional transparency applied to src
* @param mask Optional parameter with mask definition (0-skip, other-copy)
* @param mask Optional parameter with mask definition
* @param maskOnly Optional parameter for using mask over transColor
*/
void transBlitFrom(const Surface &src, const Common::Rect &srcRect, const Common::Rect &destRect,
@ -376,7 +374,7 @@ public:
* Copies another surface into this one ignoring pixels of a designated transparent color
* @param src Source surface
* @param destPos Destination position to draw the surface
* @param mask Mask definition (0-skip, other-copy)
* @param mask Mask definition
*/
void transBlitFrom(const ManagedSurface &src, const Common::Point &destPos,
const ManagedSurface &mask);
@ -406,6 +404,8 @@ public:
* @param overrideColor Optional color to use instead of non-transparent pixels from
* the source surface
* @param srcAlpha Optional additional transparency applied to src
* @param mask Optional parameter with mask definition
* @param maskOnly Optional parameter for using mask over transColor
*/
void transBlitFrom(const ManagedSurface &src, const Common::Rect &srcRect, const Common::Rect &destRect,
uint transColor = 0, bool flipped = false, uint overrideColor = 0, uint srcAlpha = 0xff,