/* ScummVM - Graphic Adventure Engine * * ScummVM is the legal property of its developers, whose names * are too numerous to list here. Please refer to the COPYRIGHT * file distributed with this source distribution. * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * */ #include "graphics/managed_surface.h" #include "common/algorithm.h" #include "common/textconsole.h" #include "common/endian.h" namespace Graphics { const int SCALE_THRESHOLD = 0x100; ManagedSurface::ManagedSurface() : w(_innerSurface.w), h(_innerSurface.h), pitch(_innerSurface.pitch), format(_innerSurface.format), _disposeAfterUse(DisposeAfterUse::NO), _owner(nullptr), _transparentColor(0),_transparentColorSet(false), _paletteSet(false) { Common::fill(&_palette[0], &_palette[256], 0); } ManagedSurface::ManagedSurface(const ManagedSurface &surf) : w(_innerSurface.w), h(_innerSurface.h), pitch(_innerSurface.pitch), format(_innerSurface.format), _disposeAfterUse(DisposeAfterUse::NO), _owner(nullptr), _transparentColor(0), _transparentColorSet(false), _paletteSet(false) { Common::fill(&_palette[0], &_palette[256], 0); *this = surf; } ManagedSurface::ManagedSurface(int width, int height) : w(_innerSurface.w), h(_innerSurface.h), pitch(_innerSurface.pitch), format(_innerSurface.format), _disposeAfterUse(DisposeAfterUse::NO), _owner(nullptr), _transparentColor(0), _transparentColorSet(false), _paletteSet(false) { Common::fill(&_palette[0], &_palette[256], 0); create(width, height); } ManagedSurface::ManagedSurface(int width, int height, const Graphics::PixelFormat &pixelFormat) : w(_innerSurface.w), h(_innerSurface.h), pitch(_innerSurface.pitch), format(_innerSurface.format), _disposeAfterUse(DisposeAfterUse::NO), _owner(nullptr), _transparentColor(0), _transparentColorSet(false), _paletteSet(false) { Common::fill(&_palette[0], &_palette[256], 0); create(width, height, pixelFormat); } ManagedSurface::ManagedSurface(ManagedSurface &surf, const Common::Rect &bounds) : w(_innerSurface.w), h(_innerSurface.h), pitch(_innerSurface.pitch), format(_innerSurface.format), _disposeAfterUse(DisposeAfterUse::NO), _owner(nullptr), _transparentColor(0), _transparentColorSet(false), _paletteSet(false) { Common::fill(&_palette[0], &_palette[256], 0); create(surf, bounds); } ManagedSurface::ManagedSurface(Surface *surf, DisposeAfterUse::Flag disposeAfterUse) : w(_innerSurface.w), h(_innerSurface.h), pitch(_innerSurface.pitch), format(_innerSurface.format), _owner(nullptr), _transparentColor(0), _transparentColorSet(false), _paletteSet(false) { if (!surf) { _disposeAfterUse = DisposeAfterUse::YES; return; } if (disposeAfterUse == DisposeAfterUse::YES) { _innerSurface.w = surf->w; _innerSurface.h = surf->h; _innerSurface.pitch = surf->pitch; _innerSurface.format = surf->format; _innerSurface.setPixels(surf->getPixels()); delete surf; } else { copyFrom(*surf); } } ManagedSurface::ManagedSurface(const Surface *surf) : w(_innerSurface.w), h(_innerSurface.h), pitch(_innerSurface.pitch), format(_innerSurface.format), _owner(nullptr), _transparentColor(0), _transparentColorSet(false), _paletteSet(false) { if (!surf) { _disposeAfterUse = DisposeAfterUse::YES; return; } copyFrom(*surf); _disposeAfterUse = DisposeAfterUse::NO; } ManagedSurface::~ManagedSurface() { free(); } ManagedSurface &ManagedSurface::operator=(const ManagedSurface &surf) { // Free any current surface free(); if (surf._disposeAfterUse == DisposeAfterUse::YES) { // Create a new surface and copy the pixels from the source surface create(surf.w, surf.h, surf.format); Common::copy((const byte *)surf.getPixels(), (const byte *)surf.getPixels() + surf.w * surf.h * surf.format.bytesPerPixel, (byte *)this->getPixels()); } else { // Source isn't managed, so simply copy its fields _owner = surf._owner; _offsetFromOwner = surf._offsetFromOwner; void *srcPixels = const_cast(surf._innerSurface.getPixels()); _innerSurface.setPixels(srcPixels); _innerSurface.w = surf.w; _innerSurface.h = surf.h; _innerSurface.pitch = surf.pitch; this->format = surf.format; // Copy miscellaneous properties _transparentColorSet = surf._transparentColorSet; _transparentColor = surf._transparentColor; _paletteSet = surf._paletteSet; Common::copy(&surf._palette[0], &surf._palette[256], _palette); } return *this; } void ManagedSurface::setPixels(void *newPixels) { free(); _innerSurface.setPixels(newPixels); } void ManagedSurface::create(uint16 width, uint16 height) { create(width, height, PixelFormat::createFormatCLUT8()); } void ManagedSurface::create(uint16 width, uint16 height, const PixelFormat &pixelFormat) { free(); _innerSurface.create(width, height, pixelFormat); // For pixel formats with an alpha channel, we need to do a clear // so that all the pixels will have full alpha (0xff) if (pixelFormat.aBits() != 0) clear(0); _disposeAfterUse = DisposeAfterUse::YES; markAllDirty(); } void ManagedSurface::create(ManagedSurface &surf, const Common::Rect &bounds) { free(); _offsetFromOwner = Common::Point(bounds.left, bounds.top); _innerSurface.setPixels(surf.getBasePtr(bounds.left, bounds.top)); _innerSurface.pitch = surf.pitch; _innerSurface.format = surf.format; _innerSurface.w = bounds.width(); _innerSurface.h = bounds.height(); _owner = &surf; _disposeAfterUse = DisposeAfterUse::NO; // Copy miscellaneous properties _transparentColorSet = surf._transparentColorSet; _transparentColor = surf._transparentColor; _paletteSet = surf._paletteSet; Common::copy(&surf._palette[0], &surf._palette[256], _palette); } void ManagedSurface::free() { if (_disposeAfterUse == DisposeAfterUse::YES) _innerSurface.free(); _disposeAfterUse = DisposeAfterUse::NO; _owner = nullptr; _offsetFromOwner = Common::Point(0, 0); _transparentColorSet = false; _paletteSet = false; } void ManagedSurface::copyFrom(const ManagedSurface &surf) { // Surface::copyFrom frees pixel pointer so let's free up ManagedSurface to be coherent free(); // Copy the surface _innerSurface.copyFrom(surf._innerSurface); markAllDirty(); // Pixels data is now owned by us _disposeAfterUse = DisposeAfterUse::YES; // Copy miscellaneous properties _transparentColorSet = surf._transparentColorSet; _transparentColor = surf._transparentColor; _paletteSet = surf._paletteSet; Common::copy(&surf._palette[0], &surf._palette[256], _palette); } void ManagedSurface::copyFrom(const Surface &surf) { // Surface::copyFrom frees pixel pointer so let's free up ManagedSurface to be coherent free(); // Copy the surface _innerSurface.copyFrom(surf); markAllDirty(); // Pixels data is now owned by us _disposeAfterUse = DisposeAfterUse::YES; // Set miscellaneous properties to sane values _transparentColorSet = false; _transparentColor = 0; _paletteSet = false; Common::fill(&_palette[0], &_palette[256], 0); } bool ManagedSurface::clip(Common::Rect &srcBounds, Common::Rect &destBounds) { if (destBounds.left >= this->w || destBounds.top >= this->h || destBounds.right <= 0 || destBounds.bottom <= 0) return false; // Clip the bounds if necessary to fit on-screen if (destBounds.right > this->w) { srcBounds.right -= destBounds.right - this->w; destBounds.right = this->w; } if (destBounds.bottom > this->h) { srcBounds.bottom -= destBounds.bottom - this->h; destBounds.bottom = this->h; } if (destBounds.top < 0) { srcBounds.top += -destBounds.top; destBounds.top = 0; } if (destBounds.left < 0) { srcBounds.left += -destBounds.left; destBounds.left = 0; } return true; } void ManagedSurface::blitFrom(const Surface &src) { blitFrom(src, Common::Rect(0, 0, src.w, src.h), Common::Point(0, 0)); } void ManagedSurface::blitFrom(const Surface &src, const Common::Point &destPos) { blitFrom(src, Common::Rect(0, 0, src.w, src.h), destPos); } void ManagedSurface::blitFrom(const Surface &src, const Common::Rect &srcRect, const Common::Point &destPos) { blitFromInner(src, srcRect, Common::Rect(destPos.x, destPos.y, destPos.x + srcRect.width(), destPos.y + srcRect.height()), nullptr); } void ManagedSurface::blitFrom(const Surface &src, const Common::Rect &srcRect, const Common::Rect &destRect) { blitFromInner(src, srcRect, destRect, nullptr); } void ManagedSurface::blitFrom(const ManagedSurface &src) { blitFrom(src, Common::Rect(0, 0, src.w, src.h), Common::Point(0, 0)); } void ManagedSurface::blitFrom(const ManagedSurface &src, const Common::Point &destPos) { blitFrom(src, Common::Rect(0, 0, src.w, src.h), destPos); } void ManagedSurface::blitFrom(const ManagedSurface &src, const Common::Rect &srcRect, const Common::Point &destPos) { if (src._transparentColorSet) transBlitFrom(src, srcRect, destPos); else blitFromInner(src._innerSurface, srcRect, Common::Rect(destPos.x, destPos.y, destPos.x + srcRect.width(), destPos.y + srcRect.height()), src._paletteSet ? src._palette : nullptr); } void ManagedSurface::blitFrom(const ManagedSurface &src, const Common::Rect &srcRect, const Common::Rect &destRect) { if (src._transparentColorSet) transBlitFrom(src, srcRect, destRect); else blitFromInner(src._innerSurface, srcRect, destRect, src._paletteSet ? src._palette : nullptr); } void ManagedSurface::blitFromInner(const Surface &src, const Common::Rect &srcRect, const Common::Rect &destRect, const uint32 *srcPalette) { if (destRect.isEmpty()) return; const int scaleX = SCALE_THRESHOLD * srcRect.width() / destRect.width(); const int scaleY = SCALE_THRESHOLD * srcRect.height() / destRect.height(); uint destPixel; byte rSrc, gSrc, bSrc, aSrc; byte aDest = 0, rDest = 0, gDest = 0, bDest = 0; if (!srcRect.isValidRect()) return; if (format != src.format) { // When the pixel format differs, the destination must be non-paletted assert(format.bytesPerPixel == 2 || format.bytesPerPixel == 3 || format.bytesPerPixel == 4); assert(src.format.bytesPerPixel == 2 || src.format.bytesPerPixel == 4 || (src.format.bytesPerPixel == 1 && srcPalette)); } const bool noScale = scaleX == SCALE_THRESHOLD && scaleY == SCALE_THRESHOLD; for (int destY = destRect.top, scaleYCtr = 0; destY < destRect.bottom; ++destY, scaleYCtr += scaleY) { if (destY < 0 || destY >= h) continue; const byte *srcP = (const byte *)src.getBasePtr(srcRect.left, scaleYCtr / SCALE_THRESHOLD + srcRect.top); byte *destP = (byte *)getBasePtr(destRect.left, destY); // For paletted format, assume the palette is the same and there is no transparency. // We can thus do a straight copy of the pixels. if (format.bytesPerPixel == 1 && noScale) { int width = srcRect.width(); if (destRect.left + width > w) width = w - destRect.left; if (destRect.left < 0) { srcP -= destRect.left; destP -= destRect.left; width += destRect.left; } if (width > 0) Common::copy(srcP, srcP + width, destP); continue; } // Loop through drawing the pixels of the row for (int destX = destRect.left, xCtr = 0, scaleXCtr = 0; destX < destRect.right; ++destX, ++xCtr, scaleXCtr += scaleX) { if (destX < 0 || destX >= w) continue; const byte *srcVal = &srcP[scaleXCtr / SCALE_THRESHOLD * src.format.bytesPerPixel]; byte *destVal = &destP[xCtr * format.bytesPerPixel]; if (format.bytesPerPixel == 1) { *destVal = *srcVal; continue; } if (src.format.bytesPerPixel == 1) { assert(srcPalette != nullptr); // Catch the cases when palette is missing // Get the palette color const uint32 col = srcPalette[*srcVal]; rSrc = col & 0xff; gSrc = (col >> 8) & 0xff; bSrc = (col >> 16) & 0xff; aSrc = (col >> 24) & 0xff; } else { // Use the src's pixel format to split up the source pixel src.format.colorToARGB(src.format.bytesPerPixel == 2 ? *(const uint16 *)srcVal : *(const uint32 *)srcVal, aSrc, rSrc, gSrc, bSrc); } if (aSrc == 0) { // Completely transparent, so skip continue; } else if (aSrc == 0xff) { // Completely opaque, so copy RGB values over aDest = aSrc; rDest = rSrc; gDest = gSrc; bDest = bSrc; } else { // Partially transparent, so calculate new pixel colors if (format.bytesPerPixel == 2) { uint32 destColor = *(uint16 *)destVal; format.colorToARGB(destColor, aDest, rDest, gDest, bDest); } else if (format.bytesPerPixel == 4) { uint32 destColor = *(uint32 *)destVal; format.colorToARGB(destColor, aDest, rDest, gDest, bDest); } else { aDest = 0xFF; rDest = destVal[0]; gDest = destVal[1]; bDest = destVal[2]; } double sAlpha = (double)aSrc / 255.0; double dAlpha = (double)aDest / 255.0; dAlpha *= (1.0 - sAlpha); rDest = static_cast((rSrc * sAlpha + rDest * dAlpha) / (sAlpha + dAlpha)); gDest = static_cast((gSrc * sAlpha + gDest * dAlpha) / (sAlpha + dAlpha)); bDest = static_cast((bSrc * sAlpha + bDest * dAlpha) / (sAlpha + dAlpha)); aDest = static_cast(255. * (sAlpha + dAlpha)); } destPixel = format.ARGBToColor(aDest, rDest, gDest, bDest); if (format.bytesPerPixel == 2) *(uint16 *)destVal = destPixel; else if (format.bytesPerPixel == 4) *(uint32 *)destVal = destPixel; else WRITE_UINT24(destVal, destPixel); } } addDirtyRect(Common::Rect(0, 0, this->w, this->h)); } void ManagedSurface::transBlitFrom(const Surface &src, uint transColor, bool flipped, uint overrideColor, uint srcAlpha) { transBlitFrom(src, Common::Rect(0, 0, src.w, src.h), Common::Rect(0, 0, this->w, this->h), transColor, flipped, overrideColor, srcAlpha); } void ManagedSurface::transBlitFrom(const Surface &src, const Common::Point &destPos, uint transColor, bool flipped, uint overrideColor, uint srcAlpha) { transBlitFrom(src, Common::Rect(0, 0, src.w, src.h), Common::Rect(destPos.x, destPos.y, destPos.x + src.w, destPos.y + src.h), transColor, flipped, overrideColor, srcAlpha); } void ManagedSurface::transBlitFrom(const Surface &src, const Common::Point &destPos, const ManagedSurface &mask) { transBlitFrom(src, Common::Rect(0, 0, src.w, src.h), Common::Rect(destPos.x, destPos.y, destPos.x + src.w, destPos.y + src.h), 0, false, 0, 0xff, &mask._innerSurface, true); } void ManagedSurface::transBlitFrom(const Surface &src, const Common::Point &destPos, const Surface &mask) { transBlitFrom(src, Common::Rect(0, 0, src.w, src.h), Common::Rect(destPos.x, destPos.y, destPos.x + src.w, destPos.y + src.h), 0, false, 0, 0xff, &mask, true); } void ManagedSurface::transBlitFrom(const Surface &src, const Common::Rect &srcRect, const Common::Point &destPos, uint transColor, bool flipped, uint overrideColor, uint srcAlpha) { transBlitFrom(src, srcRect, Common::Rect(destPos.x, destPos.y, destPos.x + srcRect.width(), destPos.y + srcRect.height()), transColor, flipped, overrideColor, srcAlpha); } void ManagedSurface::transBlitFrom(const Surface &src, const Common::Rect &srcRect, const Common::Rect &destRect, uint transColor, bool flipped, uint overrideColor, uint srcAlpha, const Surface *mask, bool maskOnly) { transBlitFromInner(src, srcRect, destRect, transColor, flipped, overrideColor, srcAlpha, nullptr, nullptr, mask, maskOnly); } void ManagedSurface::transBlitFrom(const ManagedSurface &src, uint transColor, bool flipped, uint overrideColor, uint srcAlpha) { transBlitFrom(src, Common::Rect(0, 0, src.w, src.h), Common::Rect(0, 0, this->w, this->h), transColor, flipped, overrideColor, srcAlpha); } void ManagedSurface::transBlitFrom(const ManagedSurface &src, const Common::Point &destPos, uint transColor, bool flipped, uint overrideColor, uint srcAlpha) { transBlitFrom(src, Common::Rect(0, 0, src.w, src.h), Common::Rect(destPos.x, destPos.y, destPos.x + src.w, destPos.y + src.h), transColor, flipped, overrideColor, srcAlpha); } void ManagedSurface::transBlitFrom(const ManagedSurface &src, const Common::Point &destPos, const ManagedSurface &mask) { transBlitFrom(src, Common::Rect(0, 0, src.w, src.h), Common::Rect(destPos.x, destPos.y, destPos.x + src.w, destPos.y + src.h), 0, false, 0, 0xff, &mask._innerSurface, true); } void ManagedSurface::transBlitFrom(const ManagedSurface &src, const Common::Rect &srcRect, const Common::Point &destPos, uint transColor, bool flipped, uint overrideColor, uint srcAlpha) { uint tColor = !transColor && src._transparentColorSet ? src._transparentColor : transColor; transBlitFrom(src, srcRect, Common::Rect(destPos.x, destPos.y, destPos.x + srcRect.width(), destPos.y + srcRect.height()), tColor, flipped, overrideColor, srcAlpha); } void ManagedSurface::transBlitFrom(const ManagedSurface &src, const Common::Rect &srcRect, const Common::Rect &destRect, uint transColor, bool flipped, uint overrideColor, uint srcAlpha, const Surface *mask, bool maskOnly) { if (transColor == (uint)-1 && src._transparentColorSet) transColor = src._transparentColor; const uint32 *srcPalette = src._paletteSet ? src._palette : nullptr; const uint32 *dstPalette = _paletteSet ? _palette : nullptr; transBlitFromInner(src._innerSurface, srcRect, destRect, transColor, flipped, overrideColor, srcAlpha, srcPalette, dstPalette, mask, maskOnly); } static uint findBestColor(const uint32 *palette, byte cr, byte cg, byte cb) { uint bestColor = 0; double min = 0xFFFFFFFF; for (uint i = 0; i < 256; ++i) { uint col = palette[i]; int rmean = ((col & 0xff) + cr) / 2; int r = (col & 0xff) - cr; int g = ((col >> 8) & 0xff) - cg; int b = ((col >> 16) & 0xff) - cb; double dist = sqrt((((512 + rmean) * r * r) >> 8) + 4 * g * g + (((767 - rmean) * b * b) >> 8)); if (min > dist) { bestColor = i; min = dist; } } return bestColor; } static byte *createPaletteLookup(const uint32 *srcPalette, const uint32 *dstPalette) { byte *lookup = new byte[256]; for (int i = 0; i < 256; i++) { uint col = srcPalette[i]; if (col == dstPalette[i]) { lookup[i] = i; } else { lookup[i] = findBestColor(dstPalette, col & 0xff, (col >> 8) & 0xff, (col >> 16) & 0xff); } } return lookup; } template void transBlitPixel(TSRC srcVal, TDEST &destVal, const Graphics::PixelFormat &srcFormat, const Graphics::PixelFormat &destFormat, uint overrideColor, uint srcAlpha, const uint32 *srcPalette, const byte *lookup) { // Decode and re-encode each pixel byte aSrc, rSrc, gSrc, bSrc; if (srcFormat.bytesPerPixel == 1) { assert(srcPalette != nullptr); // Catch the cases when palette is missing // Get the palette color const uint32 col = srcPalette[srcVal]; rSrc = col & 0xff; gSrc = (col >> 8) & 0xff; bSrc = (col >> 16) & 0xff; aSrc = (col >> 24) & 0xff; } else { srcFormat.colorToARGB(srcVal, aSrc, rSrc, gSrc, bSrc); } if (srcAlpha != 0xff) { aSrc = aSrc * srcAlpha / 255; } byte aDest, rDest, gDest, bDest; 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; aDest = 0xff; } else { // Partially transparent, so calculate new pixel colors destFormat.colorToARGB(destVal, aDest, rDest, gDest, bDest); double sAlpha = (double)aSrc / 255.0; double dAlpha = (double)aDest / 255.0; dAlpha *= (1.0 - sAlpha); rDest = static_cast((rSrc * sAlpha + rDest * dAlpha) / (sAlpha + dAlpha)); gDest = static_cast((gSrc * sAlpha + gDest * dAlpha) / (sAlpha + dAlpha)); bDest = static_cast((bSrc * sAlpha + bDest * dAlpha) / (sAlpha + dAlpha)); aDest = static_cast(255. * (sAlpha + dAlpha)); } destVal = destFormat.ARGBToColor(aDest, rDest, gDest, bDest); } template<> void transBlitPixel(byte srcVal, byte &destVal, const Graphics::PixelFormat &srcFormat, const Graphics::PixelFormat &destFormat, uint overrideColor, uint srcAlpha, const uint32 *srcPalette, const byte *lookup) { if (srcAlpha == 0) { // Completely transparent, so skip return; } destVal = overrideColor ? overrideColor : srcVal; if (lookup) destVal = lookup[destVal]; } template void transBlit(const Surface &src, const Common::Rect &srcRect, ManagedSurface &dest, const Common::Rect &destRect, TSRC transColor, bool flipped, uint overrideColor, uint srcAlpha, const uint32 *srcPalette, const uint32 *dstPalette, const Surface *mask, bool maskOnly) { int scaleX = SCALE_THRESHOLD * srcRect.width() / destRect.width(); int scaleY = SCALE_THRESHOLD * srcRect.height() / destRect.height(); byte rst = 0, gst = 0, bst = 0, rdt = 0, gdt = 0, bdt = 0; byte r = 0, g = 0, b = 0; byte *lookup = nullptr; if (srcPalette && dstPalette) lookup = createPaletteLookup(srcPalette, dstPalette); // If we're dealing with a 32-bit source surface, we need to split up the RGB, // since we'll want to find matching RGB pixels irrespective of the alpha bool isSrcTrans32 = src.format.aBits() != 0 && transColor != (uint32)-1 && transColor > 0; if (isSrcTrans32) { src.format.colorToRGB(transColor, rst, gst, bst); } bool isDestTrans32 = dest.format.aBits() != 0 && dest.hasTransparentColor(); if (isDestTrans32) { dest.format.colorToRGB(dest.getTransparentColor(), rdt, gdt, bdt); } // Loop through drawing output lines for (int destY = destRect.top, scaleYCtr = 0; destY < destRect.bottom; ++destY, scaleYCtr += scaleY) { if (destY < 0 || destY >= dest.h) continue; const TSRC *srcLine = (const TSRC *)src.getBasePtr(srcRect.left, scaleYCtr / SCALE_THRESHOLD + srcRect.top); const TSRC *mskLine = nullptr; if (mask) mskLine = (const TSRC *)mask->getBasePtr(srcRect.left, scaleYCtr / SCALE_THRESHOLD + srcRect.top); TDEST *destLine = (TDEST *)dest.getBasePtr(destRect.left, destY); // Loop through drawing the pixels of the row for (int destX = destRect.left, xCtr = 0, scaleXCtr = 0; destX < destRect.right; ++destX, ++xCtr, scaleXCtr += scaleX) { if (destX < 0 || destX >= dest.w) continue; TSRC srcVal = srcLine[flipped ? src.w - scaleXCtr / SCALE_THRESHOLD - 1 : scaleXCtr / SCALE_THRESHOLD]; TDEST &destVal = destLine[xCtr]; dest.format.colorToRGB(destVal, r, g, b); // Check if dest pixel is transparent bool isDestPixelTrans = false; if (isDestTrans32) { dest.format.colorToRGB(destVal, r, g, b); if (rdt == r && gdt == g && bdt == b) isDestPixelTrans = true; } else if (dest.hasTransparentColor()) { isDestPixelTrans = destVal == dest.getTransparentColor(); } if (isSrcTrans32 && !maskOnly) { src.format.colorToRGB(srcVal, r, g, b); if (rst == r && gst == g && bst == b) continue; } else if (srcVal == transColor && !maskOnly) continue; if (mask) { TSRC mskVal = mskLine[flipped ? src.w - scaleXCtr / SCALE_THRESHOLD - 1 : scaleXCtr / SCALE_THRESHOLD]; if (!mskVal) continue; if (isDestPixelTrans) // Remove transparent color on dest so it isn't alpha blended destVal = 0; transBlitPixel(srcVal, destVal, src.format, dest.format, overrideColor, mskVal, srcPalette, lookup); } else { if (isDestPixelTrans) // Remove transparent color on dest so it isn't alpha blended destVal = 0; transBlitPixel(srcVal, destVal, src.format, dest.format, overrideColor, srcAlpha, srcPalette, lookup); } } } delete[] lookup; } #define HANDLE_BLIT(SRC_BYTES, DEST_BYTES, SRC_TYPE, DEST_TYPE) \ if (src.format.bytesPerPixel == SRC_BYTES && format.bytesPerPixel == DEST_BYTES) \ transBlit(src, srcRect, *this, destRect, transColor, flipped, overrideColor, srcAlpha, srcPalette, dstPalette, mask, maskOnly); \ else void ManagedSurface::transBlitFromInner(const Surface &src, const Common::Rect &srcRect, const Common::Rect &destRect, uint transColor, bool flipped, uint overrideColor, uint srcAlpha, const uint32 *srcPalette, const uint32 *dstPalette, const Surface *mask, bool maskOnly) { if (src.w == 0 || src.h == 0 || destRect.width() == 0 || destRect.height() == 0) return; if (mask) { if (mask->w != src.w || mask->h != src.h) error("Surface::transBlitFrom: mask dimensions do not match src"); } HANDLE_BLIT(1, 1, byte, byte) HANDLE_BLIT(1, 2, byte, uint16) HANDLE_BLIT(1, 4, byte, uint32) HANDLE_BLIT(2, 2, uint16, uint16) HANDLE_BLIT(4, 4, uint32, uint32) HANDLE_BLIT(2, 4, uint16, uint32) HANDLE_BLIT(4, 2, uint32, uint16) error("Surface::transBlitFrom: bytesPerPixel must be 1, 2, or 4"); // Mark the affected area addDirtyRect(destRect); } #undef HANDLE_BLIT void ManagedSurface::markAllDirty() { addDirtyRect(Common::Rect(0, 0, this->w, this->h)); } void ManagedSurface::addDirtyRect(const Common::Rect &r) { if (_owner) { Common::Rect bounds = r; bounds.clip(Common::Rect(0, 0, this->w, this->h)); bounds.translate(_offsetFromOwner.x, _offsetFromOwner.y); _owner->addDirtyRect(bounds); } } void ManagedSurface::clear(uint color) { if (!empty()) fillRect(getBounds(), color); } void ManagedSurface::setPalette(const byte *colors, uint start, uint num) { assert(start < 256 && (start + num) <= 256); uint32 *dest = &_palette[start]; for (; num > 0; --num, colors += 3) { *dest++ = colors[0] | (colors[1] << 8) | (colors[2] << 16) | (0xff << 24); } _paletteSet = true; if (_owner) _owner->setPalette(colors, start, num); } void ManagedSurface::setPalette(const uint32 *colors, uint start, uint num) { assert(start < 256 && (start + num) <= 256); Common::copy(colors, colors + num, &_palette[start]); _paletteSet = true; if (_owner) _owner->setPalette(colors, start, num); } } // End of namespace Graphics