diff options
author | Strangerke | 2013-09-08 14:49:34 +0200 |
---|---|---|
committer | Strangerke | 2013-09-08 14:49:34 +0200 |
commit | 599d2eeb06c937a4479cc751f4f9f5e94795c43b (patch) | |
tree | 6efd0f887d7a1fd5082209a585d609983031c92d /engines/wintermute/graphics/transparent_surface.cpp | |
parent | 7df4c94aeb6c1408d26d6ada58d728b6eac17717 (diff) | |
parent | 03bf56ea82c0b89f4e61e5e0787a36473f999efa (diff) | |
download | scummvm-rg350-599d2eeb06c937a4479cc751f4f9f5e94795c43b.tar.gz scummvm-rg350-599d2eeb06c937a4479cc751f4f9f5e94795c43b.tar.bz2 scummvm-rg350-599d2eeb06c937a4479cc751f4f9f5e94795c43b.zip |
Merge branch 'master' into avalanche
Diffstat (limited to 'engines/wintermute/graphics/transparent_surface.cpp')
-rw-r--r-- | engines/wintermute/graphics/transparent_surface.cpp | 215 |
1 files changed, 193 insertions, 22 deletions
diff --git a/engines/wintermute/graphics/transparent_surface.cpp b/engines/wintermute/graphics/transparent_surface.cpp index dcdcbf247e..e375322ae9 100644 --- a/engines/wintermute/graphics/transparent_surface.cpp +++ b/engines/wintermute/graphics/transparent_surface.cpp @@ -23,12 +23,123 @@ #include "common/endian.h" #include "common/util.h" #include "common/rect.h" +#include "common/math.h" #include "common/textconsole.h" #include "graphics/primitives.h" #include "engines/wintermute/graphics/transparent_surface.h" +#include "engines/wintermute/graphics/transform_tools.h" namespace Wintermute { + +#if ENABLE_BILINEAR +void TransparentSurface::copyPixelBilinear(float projX, float projY, int dstX, int dstY, const Common::Rect &srcRect, const Common::Rect &dstRect, const TransparentSurface *src, TransparentSurface *dst) { + int srcW = srcRect.width(); + int srcH = srcRect.height(); + int dstW = dstRect.width(); + int dstH = dstRect.height(); + + assert(dstX >= 0 && dstX < dstW); + assert(dstY >= 0 && dstY < dstH); + + float x1 = floor(projX); + float x2 = ceil(projX); + float y1 = floor(projY); + float y2 = ceil(projY); + + uint32 Q11, Q12, Q21, Q22; + + if (x1 >= srcW || x1 < 0 || y1 >= srcH || y1 < 0) { + Q11 = 0; + } else { + Q11 = READ_UINT32((const byte *)src->getBasePtr((int)(x1 + srcRect.left), (int)(y1 + srcRect.top))); + } + + if (x1 >= srcW || x1 < 0 || y2 >= srcH || y2 < 0) { + Q12 = 0; + } else { + Q12 = READ_UINT32((const byte *)src->getBasePtr((int)(x1 + srcRect.left), (int)(y2 + srcRect.top))); + } + + if (x2 >= srcW || x2 < 0 || y1 >= srcH || y1 < 0) { + Q21 = 0; + } else { + Q21 = READ_UINT32((const byte *)src->getBasePtr((int)(x2 + srcRect.left), (int)(y1 + srcRect.top))); + } + + if (x2 >= srcW || x2 < 0 || y2 >= srcH || y2 < 0) { + Q22 = 0; + } else { + Q22 = READ_UINT32((const byte *)src->getBasePtr((int)(x2 + srcRect.left), (int)(y2 + srcRect.top))); + } + + byte *Q11s = (byte *)&Q11; + byte *Q12s = (byte *)&Q12; + byte *Q21s = (byte *)&Q21; + byte *Q22s = (byte *)&Q22; + + uint32 color; + byte *dest = (byte *)&color; + + float q11x = (x2 - projX); + float q11y = (y2 - projY); + float q21x = (projX - x1); + float q21y = (y2 - projY); + float q12x = (x2 - projX); + float q12y = (projY - y1); + + if (x1 == x2 && y1 == y2) { + for (int c = 0; c < 4; c++) { + dest[c] = ((float)Q11s[c]); + } + } else { + + if (x1 == x2) { + q11x = 0.5; + q12x = 0.5; + q21x = 0.5; + } else if (y1 == y2) { + q11y = 0.5; + q12y = 0.5; + q21y = 0.5; + } + + for (int c = 0; c < 4; c++) { + dest[c] = (byte)( + ((float)Q11s[c]) * q11x * q11y + + ((float)Q21s[c]) * q21x * q21y + + ((float)Q12s[c]) * q12x * q12y + + ((float)Q22s[c]) * (1.0 - + q11x * q11y - + q21x * q21y - + q12x * q12y) + ); + } + } + WRITE_UINT32((byte *)dst->getBasePtr(dstX + dstRect.left, dstY + dstRect.top), color); +} +#else +void TransparentSurface::copyPixelNearestNeighbor(float projX, float projY, int dstX, int dstY, const Common::Rect &srcRect, const Common::Rect &dstRect, const TransparentSurface *src, TransparentSurface *dst) { + int srcW = srcRect.width(); + int srcH = srcRect.height(); + int dstW = dstRect.width(); + int dstH = dstRect.height(); + + assert(dstX >= 0 && dstX < dstW); + assert(dstY >= 0 && dstY < dstH); + + uint32 color; + + if (projX >= srcW || projX < 0 || projY >= srcH || projY < 0) { + color = 0; + } else { + color = READ_UINT32((const byte *)src->getBasePtr((int)projX, (int)projY)); + } + + WRITE_UINT32((byte *)dst->getBasePtr(dstX, dstY), color); +} +#endif + byte *TransparentSurface::_lookup = nullptr; void TransparentSurface::destroyLookup() { @@ -46,11 +157,14 @@ TransparentSurface::TransparentSurface(const Surface &surf, bool copyData) : Sur h = surf.h; pitch = surf.pitch; format = surf.format; - pixels = surf.pixels; + // We need to cast the const qualifier away here because 'pixels' + // always needs to be writable. 'surf' however is a constant Surface, + // thus getPixels will always return const pixel data. + pixels = const_cast<void *>(surf.getPixels()); } } -void doBlitOpaque(byte *ino, byte* outo, uint32 width, uint32 height, uint32 pitch, int32 inStep, int32 inoStep) { +void doBlitOpaque(byte *ino, byte *outo, uint32 width, uint32 height, uint32 pitch, int32 inStep, int32 inoStep) { byte *in, *out; #ifdef SCUMM_LITTLE_ENDIAN @@ -81,7 +195,7 @@ void TransparentSurface::generateLookup() { } } -void TransparentSurface::doBlitAlpha(byte *ino, byte* outo, uint32 width, uint32 height, uint32 pitch, int32 inStep, int32 inoStep) { +void TransparentSurface::doBlitAlpha(byte *ino, byte *outo, uint32 width, uint32 height, uint32 pitch, int32 inStep, int32 inoStep) { byte *in, *out; if (!_lookup) { @@ -195,16 +309,28 @@ Common::Rect TransparentSurface::blit(Graphics::Surface &target, int posX, int p } if (pPartRect) { - srcImage.pixels = &((char *)pixels)[pPartRect->top * srcImage.pitch + pPartRect->left * 4]; + + int xOffset = pPartRect->left; + int yOffset = pPartRect->top; + + if (flipping & FLIP_V) { + yOffset = srcImage.h - pPartRect->bottom; + } + + if (flipping & FLIP_H) { + xOffset = srcImage.w - pPartRect->right; + } + + srcImage.pixels = getBasePtr(xOffset, yOffset); srcImage.w = pPartRect->width(); srcImage.h = pPartRect->height(); debug(6, "Blit(%d, %d, %d, [%d, %d, %d, %d], %08x, %d, %d)", posX, posY, flipping, - pPartRect->left, pPartRect->top, pPartRect->width(), pPartRect->height(), color, width, height); + pPartRect->left, pPartRect->top, pPartRect->width(), pPartRect->height(), color, width, height); } else { debug(6, "Blit(%d, %d, %d, [%d, %d, %d, %d], %08x, %d, %d)", posX, posY, flipping, 0, 0, - srcImage.w, srcImage.h, color, width, height); + srcImage.w, srcImage.h, color, width, height); } if (width == -1) @@ -224,7 +350,7 @@ Common::Rect TransparentSurface::blit(Graphics::Surface &target, int posX, int p if ((width != srcImage.w) || (height != srcImage.h)) { // Scale the image img = imgScaled = srcImage.scale(width, height); - savedPixels = (byte *)img->pixels; + savedPixels = (byte *)img->getPixels(); } else { img = &srcImage; } @@ -232,13 +358,13 @@ Common::Rect TransparentSurface::blit(Graphics::Surface &target, int posX, int p // Handle off-screen clipping if (posY < 0) { img->h = MAX(0, (int)img->h - -posY); - img->pixels = (byte *)img->pixels + img->pitch * -posY; + img->setPixels((byte *)img->getBasePtr(0, -posY)); posY = 0; } if (posX < 0) { img->w = MAX(0, (int)img->w - -posX); - img->pixels = (byte *)img->pixels + (-posX * 4); + img->setPixels((byte *)img->getBasePtr(-posX, 0)); posX = 0; } @@ -250,12 +376,12 @@ Common::Rect TransparentSurface::blit(Graphics::Surface &target, int posX, int p int inStep = 4; int inoStep = img->pitch; - if (flipping & TransparentSurface::FLIP_V) { + if (flipping & TransparentSurface::FLIP_H) { inStep = -inStep; xp = img->w - 1; } - if (flipping & TransparentSurface::FLIP_H) { + if (flipping & TransparentSurface::FLIP_V) { inoStep = -inoStep; yp = img->h - 1; } @@ -375,7 +501,7 @@ Common::Rect TransparentSurface::blit(Graphics::Surface &target, int posX, int p retSize.setHeight(img->h); if (imgScaled) { - imgScaled->pixels = savedPixels; + imgScaled->setPixels(savedPixels); imgScaled->free(); delete imgScaled; } @@ -383,16 +509,54 @@ Common::Rect TransparentSurface::blit(Graphics::Surface &target, int posX, int p return retSize; } +TransparentSurface *TransparentSurface::rotoscale(const TransformStruct &transform) const { + + assert(transform._angle != 0); // This would not be ideal; rotoscale() should never be called in conditional branches where angle = 0 anyway. + + Point32 newHotspot; + Common::Rect srcRect(0, 0, (int16)w, (int16)h); + Rect32 rect = TransformTools::newRect(Rect32(srcRect), transform, &newHotspot); + Common::Rect dstRect(0, 0, (int16)(rect.right - rect.left), (int16)(rect.bottom - rect.top)); + + TransparentSurface *target = new TransparentSurface(); + assert(format.bytesPerPixel == 4); + + int dstW = dstRect.width(); + int dstH = dstRect.height(); + + target->create((uint16)dstW, (uint16)dstH, this->format); + + uint32 invAngle = 360 - (transform._angle % 360); + float invCos = cos(invAngle * M_PI / 180.0); + float invSin = sin(invAngle * M_PI / 180.0); + float targX; + float targY; + + for (int y = 0; y < dstH; y++) { + for (int x = 0; x < dstW; x++) { + int x1 = x - newHotspot.x; + int y1 = y - newHotspot.y; + + targX = ((x1 * invCos - y1 * invSin)) * kDefaultZoomX / transform._zoom.x + srcRect.left; + targY = ((x1 * invSin + y1 * invCos)) * kDefaultZoomY / transform._zoom.y + srcRect.top; + + targX += transform._hotspot.x; + targY += transform._hotspot.y; + +#if ENABLE_BILINEAR + copyPixelBilinear(targX, targY, x, y, srcRect, dstRect, this, target); +#else + copyPixelNearestNeighbor(targX, targY, x, y, srcRect, dstRect, this, target); +#endif + } + } + return target; +} + TransparentSurface *TransparentSurface::scale(uint16 newWidth, uint16 newHeight) const { Common::Rect srcRect(0, 0, (int16)w, (int16)h); Common::Rect dstRect(0, 0, (int16)newWidth, (int16)newHeight); - return scale(srcRect, dstRect); -} -// Copied from clone2727's https://github.com/clone2727/scummvm/blob/pegasus/engines/pegasus/surface.cpp#L247 -TransparentSurface *TransparentSurface::scale(const Common::Rect &srcRect, const Common::Rect &dstRect) const { - // I'm doing simple linear scaling here - // dstRect(x, y) = srcRect(x * srcW / dstW, y * srcH / dstH); TransparentSurface *target = new TransparentSurface(); assert(format.bytesPerPixel == 4); @@ -404,11 +568,18 @@ TransparentSurface *TransparentSurface::scale(const Common::Rect &srcRect, const target->create((uint16)dstW, (uint16)dstH, this->format); + + float projX; + float projY; for (int y = 0; y < dstH; y++) { for (int x = 0; x < dstW; x++) { - uint32 color = READ_UINT32((const byte *)getBasePtr(x * srcW / dstW + srcRect.left, - y * srcH / dstH + srcRect.top)); - WRITE_UINT32((byte *)target->getBasePtr(x + dstRect.left, y + dstRect.top), color); + projX = x / (float)dstW * srcW; + projY = y / (float)dstH * srcH; +#if ENABLE_BILINEAR + copyPixelBilinear(projX, projY, x, y, srcRect, dstRect, this, target); +#else + copyPixelNearestNeighbor(projX, projY, x, y, srcRect, dstRect, this, target); +#endif } } return target; @@ -440,4 +611,4 @@ void TransparentSurface::applyColorKey(uint8 rKey, uint8 gKey, uint8 bKey, bool } } -} // End of namespace Graphics +} // End of namespace Wintermute |