diff options
Diffstat (limited to 'engines/sword25/gfx/image/renderedimage.cpp')
-rw-r--r-- | engines/sword25/gfx/image/renderedimage.cpp | 324 |
1 files changed, 183 insertions, 141 deletions
diff --git a/engines/sword25/gfx/image/renderedimage.cpp b/engines/sword25/gfx/image/renderedimage.cpp index 27ee4ef182..c8a6666046 100644 --- a/engines/sword25/gfx/image/renderedimage.cpp +++ b/engines/sword25/gfx/image/renderedimage.cpp @@ -38,6 +38,8 @@ #include "sword25/gfx/image/imgloader.h" #include "sword25/gfx/image/renderedimage.h" +#include "sword25/gfx/renderobjectmanager.h" + #include "common/system.h" namespace Sword25 { @@ -99,7 +101,8 @@ static byte *readSavegameThumbnail(const Common::String &filename, uint &fileSiz RenderedImage::RenderedImage(const Common::String &filename, bool &result) : _data(0), _width(0), - _height(0) { + _height(0), + _isTransparent(true) { result = false; PackageManager *pPackage = Kernel::getInstance()->getPackage(); @@ -142,6 +145,11 @@ RenderedImage::RenderedImage(const Common::String &filename, bool &result) : _doCleanup = true; +#if defined(SCUMM_LITTLE_ENDIAN) + // Makes sense for LE only at the moment + checkForTransparency(); +#endif + return; } @@ -149,7 +157,8 @@ RenderedImage::RenderedImage(const Common::String &filename, bool &result) : RenderedImage::RenderedImage(uint width, uint height, bool &result) : _width(width), - _height(height) { + _height(height), + _isTransparent(true) { _data = new byte[width * height * 4]; Common::fill(_data, &_data[width * height * 4], 0); @@ -162,7 +171,7 @@ RenderedImage::RenderedImage(uint width, uint height, bool &result) : return; } -RenderedImage::RenderedImage() : _width(0), _height(0), _data(0) { +RenderedImage::RenderedImage() : _width(0), _height(0), _data(0), _isTransparent(true) { _backSurface = Kernel::getInstance()->getGfx()->getSurface(); _doCleanup = false; @@ -219,7 +228,7 @@ uint RenderedImage::getPixel(int x, int y) { // ----------------------------------------------------------------------------- -bool RenderedImage::blit(int posX, int posY, int flipping, Common::Rect *pPartRect, uint color, int width, int height) { +bool RenderedImage::blit(int posX, int posY, int flipping, Common::Rect *pPartRect, uint color, int width, int height, RectangleList *updateRects) { int ca = (color >> 24) & 0xff; // Check if we need to draw anything at all @@ -282,156 +291,175 @@ bool RenderedImage::blit(int posX, int posY, int flipping, Common::Rect *pPartRe img = &srcImage; } - // Handle off-screen clipping - if (posY < 0) { - img->h = MAX(0, (int)img->h - -posY); - img->pixels = (byte *)img->pixels + img->pitch * -posY; - posY = 0; - } - - if (posX < 0) { - img->w = MAX(0, (int)img->w - -posX); - img->pixels = (byte *)img->pixels + (-posX * 4); - posX = 0; - } - - img->w = CLIP((int)img->w, 0, (int)MAX((int)_backSurface->w - posX, 0)); - img->h = CLIP((int)img->h, 0, (int)MAX((int)_backSurface->h - posY, 0)); - - if ((img->w > 0) && (img->h > 0)) { - int xp = 0, yp = 0; - - int inStep = 4; - int inoStep = img->pitch; - if (flipping & Image::FLIP_V) { - inStep = -inStep; - xp = img->w - 1; + for (RectangleList::iterator it = updateRects->begin(); it != updateRects->end(); ++it) { + const Common::Rect &clipRect = *it; + + int skipLeft = 0, skipTop = 0; + int drawX = posX, drawY = posY; + int drawWidth = img->w; + int drawHeight = img->h; + + // Handle clipping + if (drawX < clipRect.left) { + skipLeft = clipRect.left - drawX; + drawWidth -= skipLeft; + drawX = clipRect.left; } - - if (flipping & Image::FLIP_H) { - inoStep = -inoStep; - yp = img->h - 1; + + if (drawY < clipRect.top) { + skipTop = clipRect.top - drawY; + drawHeight -= skipTop; + drawY = clipRect.top; } - byte *ino = (byte *)img->getBasePtr(xp, yp); - byte *outo = (byte *)_backSurface->getBasePtr(posX, posY); - byte *in, *out; - - for (int i = 0; i < img->h; i++) { - out = outo; - in = ino; - for (int j = 0; j < img->w; j++) { - uint32 pix = *(uint32 *)in; - int b = (pix >> 0) & 0xff; - int g = (pix >> 8) & 0xff; - int r = (pix >> 16) & 0xff; - int a = (pix >> 24) & 0xff; - in += inStep; - - if (ca != 255) { - a = a * ca >> 8; - } + if (drawX + drawWidth >= clipRect.right) + drawWidth = clipRect.right - drawX; + + if (drawY + drawHeight >= clipRect.bottom) + drawHeight = clipRect.bottom - drawY; + + if ((drawWidth > 0) && (drawHeight > 0)) { + int xp = 0, yp = 0; + + int inStep = 4; + int inoStep = img->pitch; + if (flipping & Image::FLIP_V) { + inStep = -inStep; + xp = img->w - 1 - skipLeft; + } else { + xp = skipLeft; + } + + if (flipping & Image::FLIP_H) { + inoStep = -inoStep; + yp = img->h - 1 - skipTop; + } else { + yp = skipTop; + } + + byte *ino = (byte *)img->getBasePtr(xp, yp); + byte *outo = (byte *)_backSurface->getBasePtr(drawX, drawY); - switch (a) { - case 0: // Full transparency - out += 4; - break; - case 255: // Full opacity #if defined(SCUMM_LITTLE_ENDIAN) - if (cb != 255) - *out++ = (b * cb) >> 8; - else - *out++ = b; - - if (cg != 255) - *out++ = (g * cg) >> 8; - else - *out++ = g; - - if (cr != 255) - *out++ = (r * cr) >> 8; - else - *out++ = r; - - *out++ = a; + // Simple memcpy if the source bitmap doesn't have transparent pixels and the drawing transparency is 255 + // NOTE Only possible with LE-machines at the moment, maybe it would be feasible to convert the bitmap pixels at loading time? + if (!_isTransparent && ca == 255) { + for (int i = 0; i < drawHeight; i++) { + memcpy(outo, ino, drawWidth * 4); + outo += _backSurface->pitch; + ino += inoStep; + } + } else +#endif + { + byte *in, *out; + for (int i = 0; i < drawHeight; i++) { + out = outo; + in = ino; + for (int j = 0; j < drawWidth; j++) { + uint32 pix = *(uint32 *)in; + int a = (pix >> 24) & 0xff; + in += inStep; + + if (ca != 255) { + a = a * ca >> 8; + } + + if (a == 0) { + // Full transparency + out += 4; + continue; + } + + int b = (pix >> 0) & 0xff; + int g = (pix >> 8) & 0xff; + int r = (pix >> 16) & 0xff; + + if (a == 255) { +#if defined(SCUMM_LITTLE_ENDIAN) + if (cb != 255) + b = (b * cb) >> 8; + if (cg != 255) + g = (g * cg) >> 8; + if (cr != 255) + r = (r * cr) >> 8; + *(uint32 *)out = (255 << 24) | (r << 16) | (g << 8) | b; + out += 4; #else - *out++ = a; - - if (cr != 255) - *out++ = (r * cr) >> 8; - else - *out++ = r; - - if (cg != 255) - *out++ = (g * cg) >> 8; - else - *out++ = g; - - if (cb != 255) - *out++ = (b * cb) >> 8; - else - *out++ = b; + *out++ = a; + if (cr != 255) + *out++ = (r * cr) >> 8; + else + *out++ = r; + if (cg != 255) + *out++ = (g * cg) >> 8; + else + *out++ = g; + if (cb != 255) + *out++ = (b * cb) >> 8; + else + *out++ = b; #endif - break; - - default: // alpha blending + } else { #if defined(SCUMM_LITTLE_ENDIAN) - if (cb == 0) - *out = 0; - else if (cb != 255) - *out += ((b - *out) * a * cb) >> 16; - else - *out += ((b - *out) * a) >> 8; - out++; - if (cg == 0) - *out = 0; - else if (cg != 255) - *out += ((g - *out) * a * cg) >> 16; - else - *out += ((g - *out) * a) >> 8; - out++; - if (cr == 0) - *out = 0; - else if (cr != 255) - *out += ((r - *out) * a * cr) >> 16; - else - *out += ((r - *out) * a) >> 8; - out++; - *out = 255; - out++; + pix = *(uint32 *)out; + int outb = (pix >> 0) & 0xff; + int outg = (pix >> 8) & 0xff; + int outr = (pix >> 16) & 0xff; + if (cb == 0) + outb = 0; + else if (cb != 255) + outb += ((b - outb) * a * cb) >> 16; + else + outb += ((b - outb) * a) >> 8; + if (cg == 0) + outg = 0; + else if (cg != 255) + outg += ((g - outg) * a * cg) >> 16; + else + outg += ((g - outg) * a) >> 8; + if (cr == 0) + outr = 0; + else if (cr != 255) + outr += ((r - outr) * a * cr) >> 16; + else + outr += ((r - outr) * a) >> 8; + *(uint32 *)out = (255 << 24) | (outr << 16) | (outg << 8) | outb; + out += 4; #else - *out = 255; - out++; - if (cr == 0) - *out = 0; - else if (cr != 255) - *out += ((r - *out) * a * cr) >> 16; - else - *out += ((r - *out) * a) >> 8; - out++; - if (cg == 0) - *out = 0; - else if (cg != 255) - *out += ((g - *out) * a * cg) >> 16; - else - *out += ((g - *out) * a) >> 8; - out++; - if (cb == 0) - *out = 0; - else if (cb != 255) - *out += ((b - *out) * a * cb) >> 16; - else - *out += ((b - *out) * a) >> 8; - out++; + *out = 255; + out++; + if (cr == 0) + *out = 0; + else if (cr != 255) + *out += ((r - *out) * a * cr) >> 16; + else + *out += ((r - *out) * a) >> 8; + out++; + if (cg == 0) + *out = 0; + else if (cg != 255) + *out += ((g - *out) * a * cg) >> 16; + else + *out += ((g - *out) * a) >> 8; + out++; + if (cb == 0) + *out = 0; + else if (cb != 255) + *out += ((b - *out) * a * cb) >> 16; + else + *out += ((b - *out) * a) >> 8; + out++; #endif + } + } + outo += _backSurface->pitch; + ino += inoStep; } } - outo += _backSurface->pitch; - ino += inoStep; - } - g_system->copyRectToScreen(_backSurface->getBasePtr(posX, posY), _backSurface->pitch, posX, posY, - img->w, img->h); + } + } if (imgScaled) { @@ -467,6 +495,20 @@ void RenderedImage::copyDirectly(int posX, int posY) { g_system->copyRectToScreen(data, _backSurface->pitch, posX, posY, w, h); } +void RenderedImage::checkForTransparency() { + // Check if the source bitmap has any transparent pixels at all + _isTransparent = false; + byte *data = _data; + for (int i = 0; i < _height; i++) { + for (int j = 0; j < _width; j++) { + _isTransparent = data[3] != 0xff; + if (_isTransparent) + return; + data += 4; + } + } +} + /** * Scales a passed surface, creating a new surface with the result * @param srcImage Source image to scale |