diff --git a/graphics/managed_surface.cpp b/graphics/managed_surface.cpp index 583859ae046..19a54560fa3 100644 --- a/graphics/managed_surface.cpp +++ b/graphics/managed_surface.cpp @@ -30,30 +30,40 @@ const int SCALE_THRESHOLD = 0x100; ManagedSurface::ManagedSurface() : w(_innerSurface.w), h(_innerSurface.h), pitch(_innerSurface.pitch), format(_innerSurface.format), - _disposeAfterUse(DisposeAfterUse::NO), _owner(nullptr) { + _disposeAfterUse(DisposeAfterUse::NO), _owner(nullptr), + _transparentColor(0),_transparentColorSet(false), _paletteSet(false) { + Common::fill(&_palette[0], &_palette[256], 0); } ManagedSurface::ManagedSurface(ManagedSurface &surf) : w(_innerSurface.w), h(_innerSurface.h), pitch(_innerSurface.pitch), format(_innerSurface.format), - _disposeAfterUse(DisposeAfterUse::NO), _owner(nullptr) { + _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) { + _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) { + _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) { + _disposeAfterUse(DisposeAfterUse::NO), _owner(nullptr), + _transparentColor(0), _transparentColorSet(false), _paletteSet(false) { + Common::fill(&_palette[0], &_palette[256], 0); create(surf, bounds); } @@ -122,17 +132,26 @@ void ManagedSurface::free() { _disposeAfterUse = DisposeAfterUse::NO; _owner = nullptr; _offsetFromOwner = Common::Point(0, 0); + _transparentColorSet = false; + _paletteSet = false; } void ManagedSurface::copyFrom(const ManagedSurface &surf) { - // Surface::copyFrom free pixel pointer so let's free up ManagedSurface to be coherent + // 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); } bool ManagedSurface::clip(Common::Rect &srcBounds, Common::Rect &destBounds) { @@ -174,22 +193,44 @@ void ManagedSurface::blitFrom(const Surface &src, const Common::Point &destPos) void ManagedSurface::blitFrom(const Surface &src, const Common::Rect &srcRect, const Common::Point &destPos) { + blitFromInner(src, srcRect, destPos, 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, destPos, src._paletteSet ? &src._palette[0] : nullptr); +} + +void ManagedSurface::blitFromInner(const Surface &src, const Common::Rect &srcRect, + const Common::Point &destPos, const uint32 *palette) { Common::Rect srcBounds = srcRect; Common::Rect destBounds(destPos.x, destPos.y, destPos.x + srcRect.width(), destPos.y + srcRect.height()); uint destPixel; byte rSrc, gSrc, bSrc, aSrc; - byte rDest, gDest, bDest; + byte rDest = 0, gDest = 0, bDest = 0; double alpha; if (!srcRect.isValidRect() || !clip(srcBounds, destBounds)) return; if (format != src.format) { - // When the pixel format differs, both source an dest must be - // 2 or 4 bytes per pixel + // When the pixel format differs, the destination must be 2 or 4 bytes per pixel, + // and the source be 2/4 bytes as well or be paletted assert(format.bytesPerPixel == 2 || format.bytesPerPixel == 4); - assert(src.format.bytesPerPixel == 2 || src.format.bytesPerPixel == 4); + assert(src.format.bytesPerPixel == 2 || src.format.bytesPerPixel == 4 + || (src.format.bytesPerPixel == 1 && palette)); } for (int y = 0; y < srcBounds.height(); ++y) { @@ -205,8 +246,18 @@ void ManagedSurface::blitFrom(const Surface &src, const Common::Rect &srcRect, destP += format.bytesPerPixel) { src.format.colorToARGB(src.format.bytesPerPixel == 2 ? *(const uint16 *)srcP : *(const uint32 *)srcP, aSrc, rSrc, gSrc, bSrc); - format.colorToRGB(format.bytesPerPixel == 2 ? *(const uint16 *)destP : *(const uint32 *)destP, - rDest, gDest, bDest); + if (src.format.bytesPerPixel == 1) { + // Get the palette color + const uint32 col = palette[*srcP]; + 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 + format.colorToRGB(format.bytesPerPixel == 2 ? *(const uint16 *)destP : *(const uint32 *)destP, + rDest, gDest, bDest); + } if (aSrc == 0) { // Completely transparent, so skip @@ -253,8 +304,43 @@ void ManagedSurface::transBlitFrom(const Surface &src, const Common::Rect &srcRe destPos.x + srcRect.width(), destPos.y + srcRect.height()), transColor, flipped, overrideColor); } +void ManagedSurface::transBlitFrom(const Surface &src, const Common::Rect &srcRect, + const Common::Rect &destRect, uint transColor, bool flipped, uint overrideColor, uint srcAlpha) { + transBlitFromInner(src, srcRect, destRect, transColor, flipped, overrideColor, srcAlpha, nullptr); +} + +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); +} + +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); +} + +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); +} + +void ManagedSurface::transBlitFrom(const ManagedSurface &src, const Common::Rect &srcRect, + const Common::Rect &destRect, uint transColor, bool flipped, uint overrideColor, uint srcAlpha) { + if (transColor == (uint)-1 && src._transparentColorSet) + transColor = src._transparentColor; + const uint32 *palette = src._paletteSet ? src._palette : nullptr; + + transBlitFromInner(src._innerSurface, srcRect, destRect, transColor, flipped, overrideColor, + srcAlpha, palette); +} + template -void transBlit(const Surface &src, const Common::Rect &srcRect, Surface &dest, const Common::Rect &destRect, TSRC transColor, bool flipped, uint overrideColor, uint srcAlpha) { +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) { int scaleX = SCALE_THRESHOLD * srcRect.width() / destRect.width(); int scaleY = SCALE_THRESHOLD * srcRect.height() / destRect.height(); const Graphics::PixelFormat &srcFormat = src.format; @@ -284,7 +370,16 @@ void transBlit(const Surface &src, const Common::Rect &srcRect, Surface &dest, c destLine[xCtr] = overrideColor ? overrideColor : srcVal; } else { // Otherwise we have to manually decode and re-encode each pixel - srcFormat.colorToARGB(srcVal, aSrc, rSrc, gSrc, bSrc); + if (srcFormat.bytesPerPixel == 1) { + // 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) { @@ -294,12 +389,14 @@ void transBlit(const Surface &src, const Common::Rect &srcRect, Surface &dest, c if (aSrc == 0) { // Completely transparent, so skip continue; - } else if (aSrc == 0xff) { + } + else if (aSrc == 0xff) { // Completely opaque, so copy RGB values over rDest = rSrc; gDest = gSrc; bDest = bSrc; - } else { + } + else { // Partially transparent, so calculate new pixel colors alpha = (double)aSrc / 255.0; rDest = static_cast((rSrc * alpha) + (rDest * (1.0 - alpha))); @@ -315,20 +412,23 @@ void transBlit(const Surface &src, const Common::Rect &srcRect, Surface &dest, c #define HANDLE_BLIT(SRC_BYTES, DEST_BYTES, SRC_TYPE, DEST_TYPE) \ if (src.format.bytesPerPixel == SRC_BYTES && format.bytesPerPixel == DEST_BYTES) \ - transBlit(src, srcRect, _innerSurface, destRect, transColor, flipped, overrideColor, srcAlpha); \ + transBlit(src, srcRect, _innerSurface, destRect, transColor, flipped, overrideColor, srcAlpha, palette); \ else -void ManagedSurface::transBlitFrom(const Surface &src, const Common::Rect &srcRect, - const Common::Rect &destRect, uint transColor, bool flipped, uint overrideColor, uint srcAlpha) { +void ManagedSurface::transBlitFromInner(const Surface &src, const Common::Rect &srcRect, + const Common::Rect &destRect, uint transColor, bool flipped, uint overrideColor, + uint srcAlpha, const uint32 *palette) { if (src.w == 0 || src.h == 0 || destRect.width() == 0 || destRect.height() == 0) return; 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"); + error("Surface::transBlitFrom: bytesPerPixel must be 1, 2, or 4"); // Mark the affected area addDirtyRect(destRect); @@ -354,4 +454,21 @@ void ManagedSurface::clear(uint color) { 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; +} + +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; +} + } // End of namespace Graphics diff --git a/graphics/managed_surface.h b/graphics/managed_surface.h index 95671a72356..f3cff6715f8 100644 --- a/graphics/managed_surface.h +++ b/graphics/managed_surface.h @@ -61,18 +61,43 @@ private: * the offset from the parent's top-left corner this sub-surface starts at */ Common::Point _offsetFromOwner; -public: - /** - * Clips the given source bounds so the passed destBounds will be entirely on-screen - */ - bool clip(Common::Rect &srcBounds, Common::Rect &destBounds); + /** + * Automatic transparency color. When set, doesn't require transparency to be + * explicitly passed, and blit methods pass on to transBlit + */ + uint _transparentColor; + bool _transparentColorSet; + + /** + * Local palette for 8-bit images + */ + uint32 _palette[256]; + bool _paletteSet; protected: /** * Base method that descendent classes can override for recording affected * dirty areas of the surface */ virtual void addDirtyRect(const Common::Rect &r); + + /** + * Inner method for blitting + */ + void blitFromInner(const Surface &src, const Common::Rect &srcRect, + const Common::Point &destPos, const uint32 *palette); + + /** + * Inner method for copying another surface into this one at a given destination position + */ + void transBlitFromInner(const Surface &src, const Common::Rect &srcRect, + const Common::Rect &destRect, uint transColor, bool flipped, uint overrideColor, + uint srcAlpha, const uint32 *palette); +public: + /** + * Clips the given source bounds so the passed destBounds will be entirely on-screen + */ + bool clip(Common::Rect &srcBounds, Common::Rect &destBounds); public: uint16 &w; uint16 &h; @@ -229,6 +254,22 @@ public: void blitFrom(const Surface &src, const Common::Rect &srcRect, const Common::Point &destPos); + /** + * Copies another surface into this one + */ + void blitFrom(const ManagedSurface &src); + + /** + * Copies another surface into this one at a given destination position + */ + void blitFrom(const ManagedSurface &src, const Common::Point &destPos); + + /** + * Copies another surface into this one at a given destination position + */ + void blitFrom(const ManagedSurface &src, const Common::Rect &srcRect, + const Common::Point &destPos); + /** * Copies another surface into this one ignoring pixels of a designated transparent color * @param src Source surface @@ -282,6 +323,59 @@ public: void transBlitFrom(const Surface &src, const Common::Rect &srcRect, const Common::Rect &destRect, uint transColor = 0, bool flipped = false, uint overrideColor = 0, uint srcAlpha = 0xff); + /** + * Copies another surface into this one ignoring pixels of a designated transparent color + * @param src Source surface + * @param transColor Transparency color to ignore copying + * @param flipped Specifies whether to horizontally flip the image + * @param overrideColor Optional color to use instead of non-transparent pixels from + * the source surface + * @param srcAlpha Optional additional transparency applied to src + */ + void transBlitFrom(const ManagedSurface &src, uint transColor = 0, bool flipped = false, uint overrideColor = 0, uint srcAlpha = 0xff); + + /** + * 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 transColor Transparency color to ignore copying + * @param flipped Specifies whether to horizontally flip the image + * @param overrideColor Optional color to use instead of non-transparent pixels from + * the source surface + * @param srcAlpha Optional additional transparency applied to src + */ + void transBlitFrom(const ManagedSurface &src, const Common::Point &destPos, + uint transColor = 0, bool flipped = false, uint overrideColor = 0, uint srcAlpha = 0xff); + + /** + * Copies another surface into this one ignoring pixels of a designated transparent color + * @param src Source surface + * @param srcRect Sub-section of source surface to draw + * @param destPos Destination position to draw the surface + * @param transColor Transparency color to ignore copying + * @param flipped Specifies whether to horizontally flip the image + * @param overrideColor Optional color to use instead of non-transparent pixels from + * the source surface + * @param srcAlpha Optional additional transparency applied to src + */ + void transBlitFrom(const ManagedSurface &src, const Common::Rect &srcRect, const Common::Point &destPos, + uint transColor = 0, bool flipped = false, uint overrideColor = 0, uint srcAlpha = 0xff); + + /** + * Copies another surface into this one ignoring pixels of a designated transparent color + * @param src Source surface + * @param srcRect Sub-section of source surface to draw + * @param destRect Destination area to draw the surface in. This can be sized differently + * then srcRect, allowing for arbitrary scaling of the image + * @param transColor Transparency color to ignore copying + * @param flipped Specifies whether to horizontally flip the image + * @param overrideColor Optional color to use instead of non-transparent pixels from + * the source surface + * @param srcAlpha Optional additional transparency applied to src + */ + 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); + /** * Clear the entire surface */ @@ -384,6 +478,43 @@ public: void convertToInPlace(const PixelFormat &dstFormat, const byte *palette = 0) { _innerSurface.convertToInPlace(dstFormat, palette); } + + /** + * Returns the current transparent color + */ + uint getTransparentColor() const { return _transparentColor; } + + /** + * Sets the transparent color + */ + void setTransparentColor(uint color) { + _transparentColor = color; + _transparentColorSet = true; + } + + /** + * Clears the transparent color setting + */ + void clearTransparentColor() { + _transparentColorSet = false; + } + + /** + * Clear any existing palette + */ + void clearPalette() { + _paletteSet = false; + } + + /** + * Sets the palette using RGB tuplets + */ + void setPalette(const byte *colors, uint start, uint num); + + /** + * Sets the palette using RGBA values + */ + void setPalette(const uint32 *colors, uint start, uint num); }; } // End of namespace Graphics