diff options
author | Tobia Tesan | 2013-08-27 17:49:42 +0200 |
---|---|---|
committer | Einar Johan Trøan Sømåen | 2013-09-23 19:06:32 +0200 |
commit | b4161f54b6a7b99503ea2da1dab6e13523a504fe (patch) | |
tree | c72b1089fa1920d7553c978c68db1c0a94d4c274 /engines/wintermute | |
parent | c0c3854fe2bcdd7ec986c26edcce1c2d93797a19 (diff) | |
download | scummvm-rg350-b4161f54b6a7b99503ea2da1dab6e13523a504fe.tar.gz scummvm-rg350-b4161f54b6a7b99503ea2da1dab6e13523a504fe.tar.bz2 scummvm-rg350-b4161f54b6a7b99503ea2da1dab6e13523a504fe.zip |
WINTERMUTE: Add support for additive/subtractive blending in TransparentSurface
Diffstat (limited to 'engines/wintermute')
-rw-r--r-- | engines/wintermute/graphics/transparent_surface.cpp | 575 | ||||
-rw-r--r-- | engines/wintermute/graphics/transparent_surface.h | 91 |
2 files changed, 442 insertions, 224 deletions
diff --git a/engines/wintermute/graphics/transparent_surface.cpp b/engines/wintermute/graphics/transparent_surface.cpp index cd200354f7..4ba74b01de 100644 --- a/engines/wintermute/graphics/transparent_surface.cpp +++ b/engines/wintermute/graphics/transparent_surface.cpp @@ -31,9 +31,262 @@ namespace Wintermute { +void doBlitOpaqueFast(byte *ino, byte *outo, uint32 width, uint32 height, uint32 pitch, int32 inStep, int32 inoStep); +void doBlitBinaryFast(byte *ino, byte *outo, uint32 width, uint32 height, uint32 pitch, int32 inStep, int32 inoStep); + +// These gather together various blendPixel functions for use with templates. + +class BlenderAdditive { +public: + static void blendPixel(byte ina, byte inr, byte ing, byte inb, byte *outa, byte *outr, byte *outg, byte *outb); + static void blendPixel(byte ina, byte inr, byte ing, byte inb, byte *outa, byte *outr, byte *outg, byte *outb, byte *ca, byte *cr, byte *cg, byte *cb); + static void blendPixel(byte *in, byte *out); + static void blendPixel(byte *in, byte *out, int colorMod); +}; + +class BlenderSubtractive { +public: + static void blendPixel(byte ina, byte inr, byte ing, byte inb, byte *outa, byte *outr, byte *outg, byte *outb); + static void blendPixel(byte ina, byte inr, byte ing, byte inb, byte *outa, byte *outr, byte *outg, byte *outb, byte *ca, byte *cr, byte *cg, byte *cb); + static void blendPixel(byte *in, byte *out); + static void blendPixel(byte *in, byte *out, int colorMod); +}; + +class BlenderNormal { +public: + static void blendPixel(byte ina, byte inr, byte ing, byte inb, byte *outa, byte *outr, byte *outg, byte *outb); + static void blendPixel(byte ina, byte inr, byte ing, byte inb, byte *outa, byte *outr, byte *outg, byte *outb, byte *ca, byte *cr, byte *cg, byte *cb); + static void blendPixel(byte *in, byte *out); + static void blendPixel(byte *in, byte *out, int colorMod); +}; + +/** + * Perform additive blending of a pixel, applying beforehand a given colormod. + * @param ina, inr, ing, inb: the input pixel, split into its components. + * @param *outa, *outr, *outg, *outb pointer to the output pixel. + * @param *outa, *outr, *outg, *outb pointer to the colormod components. + */ + +void BlenderAdditive::blendPixel(byte ina, byte inr, byte ing, byte inb, byte *outa, byte *outr, byte *outg, byte *outb, byte *ca, byte *cr, byte *cg, byte *cb) { + + + assert(!(*cr == 255 && *ca == 255 && *cb == 255 && *cg == 255)); + // Just use the faster, sans-colormod version + + if (*ca != 255) { + ina = (ina) * (*ca) >> 8; + } + + if (ina == 0) { + return; + } else { + if (*cb != 255) + *outb = MIN(*outb + ((inb * (*cb) * ina) >> 16), 255); + else + *outb = MIN(*outb + (inb * ina >> 8), 255); + + if (*cg != 255) + *outg = MIN(*outg + ((ing * (*cg) * ina) >> 16), 255); + else + *outg = MIN(*outg + (ing * ina >> 8), 255); + + if (*cr != 255) + *outr = MIN(*outr + ((inr * (*cr) * ina) >> 16), 255); + else + *outr = MIN(*outr + (inr * ina >> 8), 255); + } +} + +/** + * Perform subtractive blending of a pixel, applying beforehand a given colormod. + * @param ina, inr, ing, inb: the input pixel, split into its components. + * @param *outa, *outr, *outg, *outb pointer to the output pixel. + * @param *outa, *outr, *outg, *outb pointer to the colormod components. + */ + +void BlenderSubtractive::blendPixel(byte ina, byte inr, byte ing, byte inb, byte *outa, byte *outr, byte *outg, byte *outb, byte *ca, byte *cr, byte *cg, byte *cb) { + + assert(!(*cr == 255 && *ca == 255 && *cb == 255 && *cg == 255)); + // Just use the faster, sans-colormod version + + //if (*ca != 255) { + // ina = ina * (*ca) >> 8; + // } + + // As weird as it is, evidence suggests that alphamod is ignored when doing + // subtractive... + + // TODO if ina == 255 fast version + + if (ina == 0) { + return; + } else { + if (*cb != 255) + *outb = MAX(*outb - ((inb * (*cb) * (*outb) * ina) >> 24), 0); + else + *outb = MAX(*outb - (inb * (*outb) * ina >> 16), 0); + + if (*cg != 255) + *outg = MAX(*outg - ((ing * (*cg) * (*outg) * ina) >> 24), 0); + else + *outg = MAX(*outg - (ing * (*outg) * ina >> 16), 0); + + if (*cr != 255) + *outr = MAX(*outr - ((inr * (*cr) * (*outr) * ina) >> 24), 0); + else + *outr = MAX(*outr - (inr * (*outr) * ina >> 16), 0); + } +} + +/** + * Perform "regular" alphablending of a pixel, applying beforehand a given colormod. + * @param ina, inr, ing, inb: the input pixel, split into its components. + * @param *outa, *outr, *outg, *outb pointer to the output pixel. + * @param *outa, *outr, *outg, *outb pointer to the colormod components. + */ + +void BlenderNormal::blendPixel(byte ina, byte inr, byte ing, byte inb, byte *outa, byte *outr, byte *outg, byte *outb, byte *ca, byte *cr, byte *cg, byte *cb) { + + assert(!(*cr == 255 && *ca == 255 && *cb == 255 && *cg == 255)); + // Just use the faster, sans-colormod version + + if (*ca != 255) { + ina = ina * (*ca) >> 8; + } + + if (ina == 0) { + return; + } else if (ina == 255) { + if (*cb != 255) + *outb = (inb * (*cb)) >> 8; + else + *outb = inb; + + if (*cr != 255) + *outr = (inr * (*cr)) >> 8; + else + *outr = inr; + + if (*cg != 255) + *outg = (ing * (*cg)) >> 8; + else + *outg = ing; + + *outa = ina; + + return; + + } else { + + *outa = 255; + *outb = (*outb * (255 - ina) >> 8); + *outr = (*outr * (255 - ina) >> 8); + *outg = (*outg * (255 - ina) >> 8); + + if (*cb == 0) + *outb = *outb; + else if (*cb != 255) + *outb = *outb + (inb * ina * (*cb) >> 16); + else + *outb = *outb + (inb * ina >> 8); + + if (*cr == 0) + *outr = *outr; + else if (*cr != 255) + *outr = *outr + (inr * ina * (*cr) >> 16); + else + *outr = *outr + (inr * ina >> 8); + + if (*cg == 0) + *outg = *outg; + else if (*cg != 255) + *outg = *outg + (ing * ina * (*cg) >> 16); + else + *outg = *outg + (ing * ina >> 8); + + return; + } +} + +/** + * Perform "regular" alphablending of a pixel. + * @param ina, inr, ing, inb: the input pixel, split into its components. + * @param *outa, *outr, *outg, *outb pointer to the output pixel. + */ + +void BlenderNormal::blendPixel(byte ina, byte inr, byte ing, byte inb, byte *outa, byte *outr, byte *outg, byte *outb) { + + if (ina == 0) { + return; + } else if (ina == 255) { + *outb = inb; + *outg = ing; + *outr = inr; + *outa = ina; + return; + } else { + *outa = 255; + *outb = ((inb * ina) + *outb * (255 - ina)) >> 8; + *outg = ((ing * ina) + *outg * (255 - ina)) >> 8; + *outr = ((inr * ina) + *outr * (255 - ina)) >> 8; + } +} + +/** + * Perform subtractive blending of a pixel. + * @param ina, inr, ing, inb: the input pixel, split into its components. + * @param *outa, *outr, *outg, *outb pointer to the output pixel. + */ + +void BlenderSubtractive::blendPixel(byte ina, byte inr, byte ing, byte inb, byte *outa, byte *outr, byte *outg, byte *outb) { + + if (ina == 0) { + return; + } else if (ina == 255) { + *outa = *outa; + *outr = *outr - (inr * (*outr) >> 8); + *outg = *outg - (ing * (*outg) >> 8); + *outb = *outb - (inb * (*outb) >> 8); + return; + } else { + *outa = *outa; + *outb = MAX(*outb - ((inb * (*outb)) * ina >> 16), 0); + *outg = MAX(*outg - ((ing * (*outg)) * ina >> 16), 0); + *outr = MAX(*outr - ((inr * (*outr)) * ina >> 16), 0); + return; + } +} + +/** + * Perform additive blending of a pixel. + * @param ina, inr, ing, inb: the input pixel, split into its components. + * @param *outa, *outr, *outg, *outb pointer to the output pixel. + */ + +void BlenderAdditive::blendPixel(byte ina, byte inr, byte ing, byte inb, byte *outa, byte *outr, byte *outg, byte *outb) { + + if (ina == 0) { + return; + } else if (ina == 255) { + *outa = *outa; + *outr = MIN(*outr + inr, 255); + *outg = MIN(*outg + ing, 255); + *outb = MIN(*outb + inb, 255); + return; + } else { + *outa = *outa; + *outb = MIN((inb * ina >> 8) + *outb, 255); + *outg = MIN((ing * ina >> 8) + *outg, 255); + *outr = MIN((inr * ina >> 8) + *outr, 255); + return; + } +} #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) { + + // TODO: Do some optimization on this. This is completely naive. + int srcW = srcRect.width(); int srcH = srcRect.height(); int dstW = dstRect.width(); @@ -106,20 +359,23 @@ void TransparentSurface::copyPixelBilinear(float projX, float projY, int dstX, i 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) - ); + ((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) { + + // TODO: Have the Rect arguments become completely useless at this point? + int srcW = srcRect.width(); int srcH = srcRect.height(); int dstW = dstRect.width(); @@ -157,21 +413,19 @@ TransparentSurface::TransparentSurface(const Surface &surf, bool copyData) : Sur } } -void doBlitOpaque(byte *ino, byte *outo, uint32 width, uint32 height, uint32 pitch, int32 inStep, int32 inoStep) { - byte *in, *out; - -#ifdef SCUMM_LITTLE_ENDIAN - const int aIndex = 0; -#else - const int aIndex = 3; -#endif +void doBlitOpaqueFast(byte *ino, byte *outo, uint32 width, uint32 height, uint32 pitch, int32 inStep, int32 inoStep) { +/** + * Optimized version of doBlit to be used w/opaque blitting (no alpha). + */ + byte *in; + byte *out; for (uint32 i = 0; i < height; i++) { out = outo; in = ino; memcpy(out, in, width * 4); for (uint32 j = 0; j < width; j++) { - out[aIndex] = 0xFF; + out[TransparentSurface::kAIndex] = 0xFF; out += 4; } outo += pitch; @@ -179,112 +433,111 @@ void doBlitOpaque(byte *ino, byte *outo, uint32 width, uint32 height, uint32 pit } } -void doBlitBinary(byte *ino, byte *outo, uint32 width, uint32 height, uint32 pitch, int32 inStep, int32 inoStep) { - byte *in, *out; - -#ifdef SCUMM_LITTLE_ENDIAN - const int aIndex = 0; -#else - const int aIndex = 3; -#endif - const int aShift = 0;//img->format.aShift; +/** + * Optimized version of doBlit to be used w/binary blitting (blit or no-blit, no blending). + */ + +void doBlitBinaryFast(byte *ino, byte *outo, uint32 width, uint32 height, uint32 pitch, int32 inStep, int32 inoStep) { + + byte *in; + byte *out; for (uint32 i = 0; i < height; i++) { out = outo; in = ino; for (uint32 j = 0; j < width; j++) { uint32 pix = *(uint32 *)in; - int a = (pix >> aShift) & 0xff; - in += inStep; + int a = (pix >> TransparentSurface::kAShift) & 0xff; if (a == 0) { // Full transparency - out += 4; } else { // Full opacity (Any value not exactly 0 is Opaque here) *(uint32 *)out = pix; - out[aIndex] = 0xFF; - out += 4; + out[TransparentSurface::kAIndex] = 0xFF; } + out += 4; + in += inStep; } outo += pitch; ino += inoStep; } } -void doBlitAlpha(byte *ino, byte *outo, uint32 width, uint32 height, uint32 pitch, int32 inStep, int32 inoStep) { - byte *in, *out; +/** + * What we have here is a template method that calls blendPixel() from a different + * class - the one we call it with - thus performing a different type of blending. + * + * @param *ino a pointer to the input surface + * @param *outo a pointer to the output surface + * @param width width of the input surface + * @param height height of the input surface + * @param pitch pitch of the output surface - that is, width in bytes of every row, usually bpp * width of the TARGET surface (the area we are blitting to might be smaller, do the math) + * @inStep size in bytes to skip to address each pixel, usually bpp of the source surface + * @inoStep width in bytes of every row on the *input* surface / kind of like pitch + * @color colormod in 0xAARRGGBB format - 0xFFFFFFFF for no colormod + */ -#ifdef SCUMM_LITTLE_ENDIAN - const int aIndex = 0; - const int bIndex = 1; - const int gIndex = 2; - const int rIndex = 3; -#else - const int aIndex = 3; - const int bIndex = 2; - const int gIndex = 1; - const int rIndex = 0; -#endif +template<class Blender> +void doBlit(byte *ino, byte *outo, uint32 width, uint32 height, uint32 pitch, int32 inStep, int32 inoStep, uint32 color) { - const int bShift = 8;//img->format.bShift; - const int gShift = 16;//img->format.gShift; - const int rShift = 24;//img->format.rShift; - const int aShift = 0;//img->format.aShift; + byte *in; + byte *out; - const int bShiftTarget = 8;//target.format.bShift; - const int gShiftTarget = 16;//target.format.gShift; - const int rShiftTarget = 24;//target.format.rShift; + if (color == 0xffffffff) { - for (uint32 i = 0; i < height; i++) { - out = outo; - in = ino; - for (uint32 j = 0; j < width; j++) { - uint32 pix = *(uint32 *)in; - uint32 oPix = *(uint32 *) out; - int b = (pix >> bShift) & 0xff; - int g = (pix >> gShift) & 0xff; - int r = (pix >> rShift) & 0xff; - int a = (pix >> aShift) & 0xff; - int outb, outg, outr, outa; - in += inStep; + for (uint32 i = 0; i < height; i++) { + out = outo; + in = ino; + for (uint32 j = 0; j < width; j++) { - switch (a) { - case 0: // Full transparency - out += 4; - break; - case 255: // Full opacity - outb = b; - outg = g; - outr = r; - outa = a; - - out[aIndex] = outa; - out[bIndex] = outb; - out[gIndex] = outg; - out[rIndex] = outr; - out += 4; - break; - - default: // alpha blending - outa = 255; - outb = ((b * a) + ((oPix >> bShiftTarget) & 0xff) * (255-a)) >> 8; - outg = ((g * a) + ((oPix >> gShiftTarget) & 0xff) * (255-a)) >> 8; - outr = ((r * a) + ((oPix >> rShiftTarget) & 0xff) * (255-a)) >> 8; - - out[aIndex] = outa; - out[bIndex] = outb; - out[gIndex] = outg; - out[rIndex] = outr; - out += 4; + byte *outa = &out[TransparentSurface::kAIndex]; + byte *outr = &out[TransparentSurface::kRIndex]; + byte *outg = &out[TransparentSurface::kGIndex]; + byte *outb = &out[TransparentSurface::kBIndex]; + + Blender::blendPixel(in[TransparentSurface::kAIndex], + in[TransparentSurface::kRIndex], + in[TransparentSurface::kGIndex], + in[TransparentSurface::kBIndex], + outa, outr, outg, outb); + + in += inStep; + out += 4; } + outo += pitch; + ino += inoStep; + } + } else { + + byte ca = (color >> TransparentSurface::kAModShift) & 0xFF; + byte cr = (color >> TransparentSurface::kRModShift) & 0xFF; + byte cg = (color >> TransparentSurface::kGModShift) & 0xFF; + byte cb = (color >> TransparentSurface::kBModShift) & 0xFF; + + for (uint32 i = 0; i < height; i++) { + out = outo; + in = ino; + for (uint32 j = 0; j < width; j++) { + + byte *outa = &out[TransparentSurface::kAIndex]; + byte *outr = &out[TransparentSurface::kRIndex]; + byte *outg = &out[TransparentSurface::kGIndex]; + byte *outb = &out[TransparentSurface::kBIndex]; + + Blender::blendPixel(in[TransparentSurface::kAIndex], + in[TransparentSurface::kRIndex], + in[TransparentSurface::kGIndex], + in[TransparentSurface::kBIndex], + outa, outr, outg, outb, &ca, &cr, &cg, &cb); + in += inStep; + out += 4; + } + outo += pitch; + ino += inoStep; } - outo += pitch; - ino += inoStep; } } - -Common::Rect TransparentSurface::blit(Graphics::Surface &target, int posX, int posY, int flipping, Common::Rect *pPartRect, uint color, int width, int height) { - int ca = (color >> 24) & 0xff; +Common::Rect TransparentSurface::blit(Graphics::Surface &target, int posX, int posY, int flipping, Common::Rect *pPartRect, uint color, int width, int height, TSpriteBlendMode blendMode) { Common::Rect retSize; retSize.top = 0; @@ -292,13 +545,11 @@ Common::Rect TransparentSurface::blit(Graphics::Surface &target, int posX, int p retSize.setWidth(0); retSize.setHeight(0); // Check if we need to draw anything at all + int ca = (color >> 24) & 0xff; + if (ca == 0) return retSize; - int cr = (color >> 16) & 0xff; - int cg = (color >> 8) & 0xff; - int cb = (color >> 0) & 0xff; - // Create an encapsulating surface for the data TransparentSurface srcImage(*this, false); // TODO: Is the data really in the screen format? @@ -325,11 +576,11 @@ Common::Rect TransparentSurface::blit(Graphics::Surface &target, int posX, int p 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) @@ -385,117 +636,24 @@ Common::Rect TransparentSurface::blit(Graphics::Surface &target, int posX, int p yp = img->h - 1; } - byte *ino = (byte *)img->getBasePtr(xp, yp); + byte *ino= (byte *)img->getBasePtr(xp, yp); byte *outo = (byte *)target.getBasePtr(posX, posY); - byte *in, *out; - -#ifdef SCUMM_LITTLE_ENDIAN - const int aIndex = 0; - const int bIndex = 1; - const int gIndex = 2; - const int rIndex = 3; -#else - const int aIndex = 3; - const int bIndex = 2; - const int gIndex = 1; - const int rIndex = 0; -#endif - const int bShift = 8;//img->format.bShift; - const int gShift = 16;//img->format.gShift; - const int rShift = 24;//img->format.rShift; - const int aShift = 0;//img->format.aShift; - - const int bShiftTarget = 8;//target.format.bShift; - const int gShiftTarget = 16;//target.format.gShift; - const int rShiftTarget = 24;//target.format.rShift; - - if (ca == 255 && cb == 255 && cg == 255 && cr == 255) { - if (_alphaMode == ALPHA_FULL) { - doBlitAlpha(ino, outo, img->w, img->h, target.pitch, inStep, inoStep); - } else if (_alphaMode == ALPHA_BINARY) { - doBlitBinary(ino, outo, img->w, img->h, target.pitch, inStep, inoStep); - } else if (_alphaMode == ALPHA_OPAQUE) { - doBlitOpaque(ino, outo, img->w, img->h, target.pitch, inStep, inoStep); - } + if (color == 0xFFFFFF && blendMode == BLEND_NORMAL && _alphaMode == ALPHA_OPAQUE) { + doBlitOpaqueFast(ino, outo, img->w, img->h, target.pitch, inStep, inoStep); + } else if (color == 0xFFFFFF && blendMode == BLEND_NORMAL && _alphaMode == ALPHA_BINARY) { + doBlitBinaryFast(ino, outo, img->w, img->h, target.pitch, inStep, inoStep); } else { - for (int i = 0; i < img->h; i++) { - out = outo; - in = ino; - for (int j = 0; j < img->w; j++) { - uint32 pix = *(uint32 *)in; - uint32 o_pix = *(uint32 *) out; - int b = (pix >> bShift) & 0xff; - int g = (pix >> gShift) & 0xff; - int r = (pix >> rShift) & 0xff; - int a = (pix >> aShift) & 0xff; - int outb, outg, outr, outa; - in += inStep; - - if (ca != 255) { - a = a * ca >> 8; - } - switch (a) { - case 0: // Full transparency - out += 4; - break; - case 255: // Full opacity - if (cb != 255) - outb = (b * cb) >> 8; - else - outb = b; - - if (cg != 255) - outg = (g * cg) >> 8; - else - outg = g; - - if (cr != 255) - outr = (r * cr) >> 8; - else - outr = r; - outa = a; - out[aIndex] = outa; - out[bIndex] = outb; - out[gIndex] = outg; - out[rIndex] = outr; - out += 4; - break; - - default: // alpha blending - outa = 255; - outb = ((o_pix >> bShiftTarget) & 0xff) * (255 - a); - outg = ((o_pix >> gShiftTarget) & 0xff) * (255 - a); - outr = ((o_pix >> rShiftTarget) & 0xff) * (255 - a); - if (cb == 0) - outb = outb >> 8; - else if (cb != 255) - outb = ((outb<<8) + b * a * cb) >> 16; - else - outb = (outb + b * a) >> 8; - if (cg == 0) - outg = outg >> 8; - else if (cg != 255) - outg = ((outg<<8) + g * a * cg) >> 16; - else - outg = (outg + g * a) >> 8; - if (cr == 0) - outr = outr >> 8; - else if (cr != 255) - outr = ((outr<<8) + r * a * cr) >> 16; - else - outr = (outr + r * a) >> 8; - out[aIndex] = outa; - out[bIndex] = outb; - out[gIndex] = outg; - out[rIndex] = outr; - out += 4; - } - } - outo += target.pitch; - ino += inoStep; + if (blendMode == BLEND_ADDITIVE) { + doBlit<BlenderAdditive>(ino, outo, img->w, img->h, target.pitch, inStep, inoStep, color); + } else if (blendMode == BLEND_SUBTRACTIVE) { + doBlit<BlenderSubtractive>(ino, outo, img->w, img->h, target.pitch, inStep, inoStep, color); + } else { + assert(blendMode == BLEND_NORMAL); + doBlit<BlenderNormal>(ino, outo, img->w, img->h, target.pitch, inStep, inoStep, color); } } + } retSize.setWidth(img->w); @@ -555,6 +713,7 @@ TransparentSurface *TransparentSurface::rotoscale(const TransformStruct &transfo } 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); diff --git a/engines/wintermute/graphics/transparent_surface.h b/engines/wintermute/graphics/transparent_surface.h index 598aaa55d7..821b5c5943 100644 --- a/engines/wintermute/graphics/transparent_surface.h +++ b/engines/wintermute/graphics/transparent_surface.h @@ -54,8 +54,28 @@ struct TransparentSurface : public Graphics::Surface { void disableColorKey(); #if ENABLE_BILINEAR + /* + * Pick color from a point in source and copy it to a pixel in target. + * The point in the source can be a float - we have subpixel accuracy in the arguments. + * We do bilinear interpolation to estimate the color of the point even if the + * point is specuified w/subpixel accuracy. + * + * @param projX, projY, point in the source to pick color from. + * @param dstX, dstY destionation pixel + * @param *src, *dst pointer to the source and dest surfaces + */ static void copyPixelBilinear(float projX, float projY, int dstX, int dstY, const Common::Rect &srcRect, const Common::Rect &dstRect, const TransparentSurface *src, TransparentSurface *dst); #else + /* + * Pick color from a point in source and copy it to a pixel in target. + * The point in the source can be a float - we have subpixel accuracy in the arguments. + * HOWEVER, this particular function just does nearest neighbor. + * Use copyPixelBilinear if you interpolation. + * + * @param projX, projY, point in the source to pick color from. + * @param dstX, dstY destionation pixel + * @param *src, *dst pointer to the source and dest surfaces + */ static void copyPixelNearestNeighbor(float projX, float projY, int dstX, int dstY, const Common::Rect &srcRect, const Common::Rect &dstRect, const TransparentSurface *src, TransparentSurface *dst); #endif // Enums @@ -63,26 +83,50 @@ struct TransparentSurface : public Graphics::Surface { @brief The possible flipping parameters for the blit methode. */ enum FLIP_FLAGS { - /// The image will not be flipped. - FLIP_NONE = 0, - /// The image will be flipped at the horizontal axis. - FLIP_H = 1, - /// The image will be flipped at the vertical axis. - FLIP_V = 2, - /// The image will be flipped at the horizontal and vertical axis. - FLIP_HV = FLIP_H | FLIP_V, - /// The image will be flipped at the horizontal and vertical axis. - FLIP_VH = FLIP_H | FLIP_V + /// The image will not be flipped. + FLIP_NONE = 0, + /// The image will be flipped at the horizontal axis. + FLIP_H = 1, + /// The image will be flipped at the vertical axis. + FLIP_V = 2, + /// The image will be flipped at the horizontal and vertical axis. + FLIP_HV = FLIP_H | FLIP_V, + /// The image will be flipped at the horizontal and vertical axis. + FLIP_VH = FLIP_H | FLIP_V }; enum AlphaType { - ALPHA_OPAQUE = 0, - ALPHA_BINARY = 1, - ALPHA_FULL = 2 + ALPHA_OPAQUE = 0, + ALPHA_BINARY = 1, + ALPHA_FULL = 2 }; AlphaType _alphaMode; + #ifdef SCUMM_LITTLE_ENDIAN + static const int kAIndex = 0; + static const int kBIndex = 1; + static const int kGIndex = 2; + static const int kRIndex = 3; + #else + static const int kAIndex = 3; + static const int kBIndex = 2; + static const int kGIndex = 1; + static const int kRIndex = 0; + #endif + + static const int kBShift = 8;//img->format.bShift; + static const int kGShift = 16;//img->format.gShift; + static const int kRShift = 24;//img->format.rShift; + static const int kAShift = 0;//img->format.aShift; + + + static const int kBModShift = 0;//img->format.bShift; + static const int kGModShift = 8;//img->format.gShift; + static const int kRModShift = 16;//img->format.rShift; + static const int kAModShift = 24;//img->format.aShift; + + /** @brief renders the surface to another surface @param pDest a pointer to the target image. In most cases this is the framebuffer. @@ -115,10 +159,26 @@ struct TransparentSurface : public Graphics::Surface { int flipping = FLIP_NONE, Common::Rect *pPartRect = nullptr, uint color = BS_ARGB(255, 255, 255, 255), - int width = -1, int height = -1); + int width = -1, int height = -1, + TSpriteBlendMode blend = BLEND_NORMAL); void applyColorKey(uint8 r, uint8 g, uint8 b, bool overwriteAlpha = false); - + + /** + * @brief Scale function; this returns a transformed version of this surface after rotation and + * scaling. Please do not use this if angle != 0, use rotoscale. + * + * @param transform a TransformStruct wrapping the required info. @see TransformStruct + * + */ TransparentSurface *scale(uint16 newWidth, uint16 newHeight) const; + + /** + * @brief Rotoscale function; this returns a transformed version of this surface after rotation and + * scaling. Please do not use this if angle == 0, use plain old scaling function. + * + * @param transform a TransformStruct wrapping the required info. @see TransformStruct + * + */ TransparentSurface *rotoscale(const TransformStruct &transform) const; }; @@ -134,7 +194,6 @@ struct TransparentSurface : public Graphics::Surface { } };*/ - } // End of namespace Wintermute |