aboutsummaryrefslogtreecommitdiff
path: root/engines/wintermute
diff options
context:
space:
mode:
Diffstat (limited to 'engines/wintermute')
-rw-r--r--engines/wintermute/graphics/transparent_surface.cpp575
-rw-r--r--engines/wintermute/graphics/transparent_surface.h91
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