ResidualVM logo ResidualVM website - Forums - Contact us BuildBot - Doxygen - Wiki curved edge

transparent_surface.cpp

Go to the documentation of this file.
00001 /* ScummVM - Graphic Adventure Engine
00002  *
00003  * ScummVM is the legal property of its developers, whose names
00004  * are too numerous to list here. Please refer to the COPYRIGHT
00005  * file distributed with this source distribution.
00006  *
00007  * This program is free software; you can redistribute it and/or
00008  * modify it under the terms of the GNU General Public License
00009  * as published by the Free Software Foundation; either version 2
00010  * of the License, or (at your option) any later version.
00011  *
00012  * This program is distributed in the hope that it will be useful,
00013  * but WITHOUT ANY WARRANTY; without even the implied warranty of
00014  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00015  * GNU General Public License for more details.
00016  *
00017  * You should have received a copy of the GNU General Public License
00018  * along with this program; if not, write to the Free Software
00019  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
00020  *
00021  *
00022  * The bottom part of this is file is adapted from SDL_rotozoom.c. The
00023  * relevant copyright notice for those specific functions can be found at the
00024  * top of that section.
00025  *
00026  */
00027 
00028 
00029 
00030 #include "common/algorithm.h"
00031 #include "common/endian.h"
00032 #include "common/util.h"
00033 #include "common/rect.h"
00034 #include "common/math.h"
00035 #include "common/textconsole.h"
00036 #include "graphics/primitives.h"
00037 #include "graphics/transparent_surface.h"
00038 #include "graphics/transform_tools.h"
00039 
00040 namespace Graphics {
00041 
00042 static const int kBModShift = 0;//img->format.bShift;
00043 static const int kGModShift = 8;//img->format.gShift;
00044 static const int kRModShift = 16;//img->format.rShift;
00045 static const int kAModShift = 24;//img->format.aShift;
00046 
00047 #ifdef SCUMM_LITTLE_ENDIAN
00048 static const int kAIndex = 0;
00049 static const int kBIndex = 1;
00050 static const int kGIndex = 2;
00051 static const int kRIndex = 3;
00052 
00053 #else
00054 static const int kAIndex = 3;
00055 static const int kBIndex = 2;
00056 static const int kGIndex = 1;
00057 static const int kRIndex = 0;
00058 #endif
00059 
00060 void doBlitOpaqueFast(byte *ino, byte *outo, uint32 width, uint32 height, uint32 pitch, int32 inStep, int32 inoStep);
00061 void doBlitBinaryFast(byte *ino, byte *outo, uint32 width, uint32 height, uint32 pitch, int32 inStep, int32 inoStep);
00062 void doBlitAlphaBlend(byte *ino, byte *outo, uint32 width, uint32 height, uint32 pitch, int32 inStep, int32 inoStep, uint32 color);
00063 void doBlitAdditiveBlend(byte *ino, byte *outo, uint32 width, uint32 height, uint32 pitch, int32 inStep, int32 inoStep, uint32 color);
00064 void doBlitSubtractiveBlend(byte *ino, byte *outo, uint32 width, uint32 height, uint32 pitch, int32 inStep, int32 inoStep, uint32 color);
00065 void doBlitMultiplyBlend(byte *ino, byte *outo, uint32 width, uint32 height, uint32 pitch, int32 inStep, int32 inoStep, uint32 color);
00066 
00067 TransparentSurface::TransparentSurface() : Surface(), _alphaMode(ALPHA_FULL) {}
00068 
00069 TransparentSurface::TransparentSurface(const Surface &surf, bool copyData) : Surface(), _alphaMode(ALPHA_FULL) {
00070     if (copyData) {
00071         copyFrom(surf);
00072     } else {
00073         w = surf.w;
00074         h = surf.h;
00075         pitch = surf.pitch;
00076         format = surf.format;
00077         // We need to cast the const qualifier away here because 'pixels'
00078         // always needs to be writable. 'surf' however is a constant Surface,
00079         // thus getPixels will always return const pixel data.
00080         pixels = const_cast<void *>(surf.getPixels());
00081     }
00082 }
00083 
00087 void doBlitOpaqueFast(byte *ino, byte *outo, uint32 width, uint32 height, uint32 pitch, int32 inStep, int32 inoStep) {
00088 
00089     byte *in;
00090     byte *out;
00091 
00092     for (uint32 i = 0; i < height; i++) {
00093         out = outo;
00094         in = ino;
00095         memcpy(out, in, width * 4);
00096         for (uint32 j = 0; j < width; j++) {
00097             out[kAIndex] = 0xFF;
00098             out += 4;
00099         }
00100         outo += pitch;
00101         ino += inoStep;
00102     }
00103 }
00104 
00108 void doBlitBinaryFast(byte *ino, byte *outo, uint32 width, uint32 height, uint32 pitch, int32 inStep, int32 inoStep) {
00109 
00110     byte *in;
00111     byte *out;
00112 
00113     for (uint32 i = 0; i < height; i++) {
00114         out = outo;
00115         in = ino;
00116         for (uint32 j = 0; j < width; j++) {
00117             uint32 pix = *(uint32 *)in;
00118             int a = in[kAIndex];
00119 
00120             if (a != 0) {   // Full opacity (Any value not exactly 0 is Opaque here)
00121                 *(uint32 *)out = pix;
00122                 out[kAIndex] = 0xFF;
00123             }
00124             out += 4;
00125             in += inStep;
00126         }
00127         outo += pitch;
00128         ino += inoStep;
00129     }
00130 }
00131 
00143 void doBlitAlphaBlend(byte *ino, byte *outo, uint32 width, uint32 height, uint32 pitch, int32 inStep, int32 inoStep, uint32 color) {
00144     byte *in;
00145     byte *out;
00146 
00147     if (color == 0xffffffff) {
00148 
00149         for (uint32 i = 0; i < height; i++) {
00150             out = outo;
00151             in = ino;
00152             for (uint32 j = 0; j < width; j++) {
00153 
00154                 if (in[kAIndex] != 0) {
00155                     out[kAIndex] = 255;
00156                     out[kRIndex] = ((in[kRIndex] * in[kAIndex]) + out[kRIndex] * (255 - in[kAIndex])) >> 8;
00157                     out[kGIndex] = ((in[kGIndex] * in[kAIndex]) + out[kGIndex] * (255 - in[kAIndex])) >> 8;
00158                     out[kBIndex] = ((in[kBIndex] * in[kAIndex]) + out[kBIndex] * (255 - in[kAIndex])) >> 8;
00159                 }
00160 
00161                 in += inStep;
00162                 out += 4;
00163             }
00164             outo += pitch;
00165             ino += inoStep;
00166         }
00167     } else {
00168 
00169         byte ca = (color >> kAModShift) & 0xFF;
00170         byte cr = (color >> kRModShift) & 0xFF;
00171         byte cg = (color >> kGModShift) & 0xFF;
00172         byte cb = (color >> kBModShift) & 0xFF;
00173 
00174         for (uint32 i = 0; i < height; i++) {
00175             out = outo;
00176             in = ino;
00177             for (uint32 j = 0; j < width; j++) {
00178 
00179                 uint32 ina = in[kAIndex] * ca >> 8;
00180                 out[kAIndex] = 255;
00181                 out[kBIndex] = (out[kBIndex] * (255 - ina) >> 8);
00182                 out[kGIndex] = (out[kGIndex] * (255 - ina) >> 8);
00183                 out[kRIndex] = (out[kRIndex] * (255 - ina) >> 8);
00184 
00185                 out[kBIndex] = out[kBIndex] + (in[kBIndex] * ina * cb >> 16);
00186                 out[kGIndex] = out[kGIndex] + (in[kGIndex] * ina * cg >> 16);
00187                 out[kRIndex] = out[kRIndex] + (in[kRIndex] * ina * cr >> 16);
00188 
00189                 in += inStep;
00190                 out += 4;
00191             }
00192             outo += pitch;
00193             ino += inoStep;
00194         }
00195     }
00196 }
00197 
00201 void doBlitAdditiveBlend(byte *ino, byte *outo, uint32 width, uint32 height, uint32 pitch, int32 inStep, int32 inoStep, uint32 color) {
00202     byte *in;
00203     byte *out;
00204 
00205     if (color == 0xffffffff) {
00206 
00207         for (uint32 i = 0; i < height; i++) {
00208             out = outo;
00209             in = ino;
00210             for (uint32 j = 0; j < width; j++) {
00211 
00212                 if (in[kAIndex] != 0) {
00213                     out[kRIndex] = MIN((in[kRIndex] * in[kAIndex] >> 8) + out[kRIndex], 255);
00214                     out[kGIndex] = MIN((in[kGIndex] * in[kAIndex] >> 8) + out[kGIndex], 255);
00215                     out[kBIndex] = MIN((in[kBIndex] * in[kAIndex] >> 8) + out[kBIndex], 255);
00216                 }
00217 
00218                 in += inStep;
00219                 out += 4;
00220             }
00221             outo += pitch;
00222             ino += inoStep;
00223         }
00224     } else {
00225 
00226         byte ca = (color >> kAModShift) & 0xFF;
00227         byte cr = (color >> kRModShift) & 0xFF;
00228         byte cg = (color >> kGModShift) & 0xFF;
00229         byte cb = (color >> kBModShift) & 0xFF;
00230 
00231         for (uint32 i = 0; i < height; i++) {
00232             out = outo;
00233             in = ino;
00234             for (uint32 j = 0; j < width; j++) {
00235 
00236                 uint32 ina = in[kAIndex] * ca >> 8;
00237 
00238                 if (cb != 255) {
00239                     out[kBIndex] = MIN<uint>(out[kBIndex] + ((in[kBIndex] * cb * ina) >> 16), 255u);
00240                 } else {
00241                     out[kBIndex] = MIN<uint>(out[kBIndex] + (in[kBIndex] * ina >> 8), 255u);
00242                 }
00243 
00244                 if (cg != 255) {
00245                     out[kGIndex] = MIN<uint>(out[kGIndex] + ((in[kGIndex] * cg * ina) >> 16), 255u);
00246                 } else {
00247                     out[kGIndex] = MIN<uint>(out[kGIndex] + (in[kGIndex] * ina >> 8), 255u);
00248                 }
00249 
00250                 if (cr != 255) {
00251                     out[kRIndex] = MIN<uint>(out[kRIndex] + ((in[kRIndex] * cr * ina) >> 16), 255u);
00252                 } else {
00253                     out[kRIndex] = MIN<uint>(out[kRIndex] + (in[kRIndex] * ina >> 8), 255u);
00254                 }
00255 
00256                 in += inStep;
00257                 out += 4;
00258             }
00259             outo += pitch;
00260             ino += inoStep;
00261         }
00262     }
00263 }
00264 
00268 void doBlitSubtractiveBlend(byte *ino, byte *outo, uint32 width, uint32 height, uint32 pitch, int32 inStep, int32 inoStep, uint32 color) {
00269     byte *in;
00270     byte *out;
00271 
00272     if (color == 0xffffffff) {
00273 
00274         for (uint32 i = 0; i < height; i++) {
00275             out = outo;
00276             in = ino;
00277             for (uint32 j = 0; j < width; j++) {
00278 
00279                 if (in[kAIndex] != 0) {
00280                     out[kRIndex] = MAX(out[kRIndex] - ((in[kRIndex] * out[kRIndex]) * in[kAIndex] >> 16), 0);
00281                     out[kGIndex] = MAX(out[kGIndex] - ((in[kGIndex] * out[kGIndex]) * in[kAIndex] >> 16), 0);
00282                     out[kBIndex] = MAX(out[kBIndex] - ((in[kBIndex] * out[kBIndex]) * in[kAIndex] >> 16), 0);
00283                 }
00284 
00285                 in += inStep;
00286                 out += 4;
00287             }
00288             outo += pitch;
00289             ino += inoStep;
00290         }
00291     } else {
00292 
00293         byte cr = (color >> kRModShift) & 0xFF;
00294         byte cg = (color >> kGModShift) & 0xFF;
00295         byte cb = (color >> kBModShift) & 0xFF;
00296 
00297         for (uint32 i = 0; i < height; i++) {
00298             out = outo;
00299             in = ino;
00300             for (uint32 j = 0; j < width; j++) {
00301 
00302                 out[kAIndex] = 255;
00303                 if (cb != 255) {
00304                     out[kBIndex] = MAX(out[kBIndex] - ((in[kBIndex] * cb  * (out[kBIndex]) * in[kAIndex]) >> 24), 0);
00305                 } else {
00306                     out[kBIndex] = MAX(out[kBIndex] - (in[kBIndex] * (out[kBIndex]) * in[kAIndex] >> 16), 0);
00307                 }
00308 
00309                 if (cg != 255) {
00310                     out[kGIndex] = MAX(out[kGIndex] - ((in[kGIndex] * cg  * (out[kGIndex]) * in[kAIndex]) >> 24), 0);
00311                 } else {
00312                     out[kGIndex] = MAX(out[kGIndex] - (in[kGIndex] * (out[kGIndex]) * in[kAIndex] >> 16), 0);
00313                 }
00314 
00315                 if (cr != 255) {
00316                     out[kRIndex] = MAX(out[kRIndex] - ((in[kRIndex] * cr * (out[kRIndex]) * in[kAIndex]) >> 24), 0);
00317                 } else {
00318                     out[kRIndex] = MAX(out[kRIndex] - (in[kRIndex] * (out[kRIndex]) * in[kAIndex] >> 16), 0);
00319                 }
00320 
00321                 in += inStep;
00322                 out += 4;
00323             }
00324             outo += pitch;
00325             ino += inoStep;
00326         }
00327     }
00328 }
00329 
00333 void doBlitMultiplyBlend(byte *ino, byte *outo, uint32 width, uint32 height, uint32 pitch, int32 inStep, int32 inoStep, uint32 color) {
00334     byte *in;
00335     byte *out;
00336 
00337     if (color == 0xffffffff) {
00338         for (uint32 i = 0; i < height; i++) {
00339             out = outo;
00340             in = ino;
00341             for (uint32 j = 0; j < width; j++) {
00342 
00343                 if (in[kAIndex] != 0) {
00344                     out[kRIndex] = MIN((in[kRIndex] * in[kAIndex] >> 8) * out[kRIndex] >> 8, 255);
00345                     out[kGIndex] = MIN((in[kGIndex] * in[kAIndex] >> 8) * out[kGIndex] >> 8, 255);
00346                     out[kBIndex] = MIN((in[kBIndex] * in[kAIndex] >> 8) * out[kBIndex] >> 8, 255);
00347                 }
00348 
00349                 in += inStep;
00350                 out += 4;
00351             }
00352             outo += pitch;
00353             ino += inoStep;
00354         }
00355     } else {
00356         byte ca = (color >> kAModShift) & 0xFF;
00357         byte cr = (color >> kRModShift) & 0xFF;
00358         byte cg = (color >> kGModShift) & 0xFF;
00359         byte cb = (color >> kBModShift) & 0xFF;
00360 
00361         for (uint32 i = 0; i < height; i++) {
00362             out = outo;
00363             in = ino;
00364             for (uint32 j = 0; j < width; j++) {
00365 
00366                 uint32 ina = in[kAIndex] * ca >> 8;
00367 
00368                 if (cb != 255) {
00369                     out[kBIndex] = MIN<uint>(out[kBIndex] * ((in[kBIndex] * cb * ina) >> 16) >> 8, 255u);
00370                 } else {
00371                     out[kBIndex] = MIN<uint>(out[kBIndex] * (in[kBIndex] * ina >> 8) >> 8, 255u);
00372                 }
00373 
00374                 if (cg != 255) {
00375                     out[kGIndex] = MIN<uint>(out[kGIndex] * ((in[kGIndex] * cg * ina) >> 16) >> 8, 255u);
00376                 } else {
00377                     out[kGIndex] = MIN<uint>(out[kGIndex] * (in[kGIndex] * ina >> 8) >> 8, 255u);
00378                 }
00379 
00380                 if (cr != 255) {
00381                     out[kRIndex] = MIN<uint>(out[kRIndex] * ((in[kRIndex] * cr * ina) >> 16) >> 8, 255u);
00382                 } else {
00383                     out[kRIndex] = MIN<uint>(out[kRIndex] * (in[kRIndex] * ina >> 8) >> 8, 255u);
00384                 }
00385 
00386                 in += inStep;
00387                 out += 4;
00388             }
00389             outo += pitch;
00390             ino += inoStep;
00391         }
00392     }
00393 
00394 }
00395 
00396 Common::Rect TransparentSurface::blit(Graphics::Surface &target, int posX, int posY, int flipping, Common::Rect *pPartRect, uint color, int width, int height, TSpriteBlendMode blendMode) {
00397 
00398     Common::Rect retSize;
00399     retSize.top = 0;
00400     retSize.left = 0;
00401     retSize.setWidth(0);
00402     retSize.setHeight(0);
00403     // Check if we need to draw anything at all
00404     int ca = (color >> kAModShift) & 0xff;
00405 
00406     if (ca == 0) {
00407         return retSize;
00408     }
00409 
00410     // Create an encapsulating surface for the data
00411     TransparentSurface srcImage(*this, false);
00412     // TODO: Is the data really in the screen format?
00413     if (format.bytesPerPixel != 4) {
00414         warning("TransparentSurface can only blit 32bpp images, but got %d", format.bytesPerPixel * 8);
00415         return retSize;
00416     }
00417 
00418     if (pPartRect) {
00419 
00420         int xOffset = pPartRect->left;
00421         int yOffset = pPartRect->top;
00422 
00423         if (flipping & FLIP_V) {
00424             yOffset = srcImage.h - pPartRect->bottom;
00425         }
00426 
00427         if (flipping & FLIP_H) {
00428             xOffset = srcImage.w - pPartRect->right;
00429         }
00430 
00431         srcImage.pixels = getBasePtr(xOffset, yOffset);
00432         srcImage.w = pPartRect->width();
00433         srcImage.h = pPartRect->height();
00434 
00435         debug(6, "Blit(%d, %d, %d, [%d, %d, %d, %d], %08x, %d, %d)", posX, posY, flipping,
00436               pPartRect->left,  pPartRect->top, pPartRect->width(), pPartRect->height(), color, width, height);
00437     } else {
00438 
00439         debug(6, "Blit(%d, %d, %d, [%d, %d, %d, %d], %08x, %d, %d)", posX, posY, flipping, 0, 0,
00440               srcImage.w, srcImage.h, color, width, height);
00441     }
00442 
00443     if (width == -1) {
00444         width = srcImage.w;
00445     }
00446     if (height == -1) {
00447         height = srcImage.h;
00448     }
00449 
00450 #ifdef SCALING_TESTING
00451     // Hardcode scaling to 66% to test scaling
00452     width = width * 2 / 3;
00453     height = height * 2 / 3;
00454 #endif
00455 
00456     Graphics::Surface *img = nullptr;
00457     Graphics::Surface *imgScaled = nullptr;
00458     byte *savedPixels = nullptr;
00459     if ((width != srcImage.w) || (height != srcImage.h)) {
00460         // Scale the image
00461         img = imgScaled = srcImage.scale(width, height);
00462         savedPixels = (byte *)img->getPixels();
00463     } else {
00464         img = &srcImage;
00465     }
00466 
00467     // Handle off-screen clipping
00468     if (posY < 0) {
00469         img->h = MAX(0, (int)img->h - -posY);
00470         if (!(flipping & FLIP_V))
00471             img->setPixels((byte *)img->getBasePtr(0, -posY));
00472         posY = 0;
00473     }
00474 
00475     if (posX < 0) {
00476         img->w = MAX(0, (int)img->w - -posX);
00477         if (!(flipping & FLIP_H))
00478             img->setPixels((byte *)img->getBasePtr(-posX, 0));
00479         posX = 0;
00480     }
00481 
00482     if (img->w > target.w - posX) {
00483         if (flipping & FLIP_H)
00484             img->setPixels((byte *)img->getBasePtr(img->w - target.w + posX, 0));
00485         img->w = CLIP((int)img->w, 0, (int)MAX((int)target.w - posX, 0));
00486     }
00487 
00488     if (img->h > target.h - posY) {
00489         if (flipping & FLIP_V)
00490             img->setPixels((byte *)img->getBasePtr(0, img->h - target.h + posY));
00491         img->h = CLIP((int)img->h, 0, (int)MAX((int)target.h - posY, 0));
00492     }
00493 
00494     // Flip surface
00495     if ((img->w > 0) && (img->h > 0)) {
00496         int xp = 0, yp = 0;
00497 
00498         int inStep = 4;
00499         int inoStep = img->pitch;
00500         if (flipping & FLIP_H) {
00501             inStep = -inStep;
00502             xp = img->w - 1;
00503         }
00504 
00505         if (flipping & FLIP_V) {
00506             inoStep = -inoStep;
00507             yp = img->h - 1;
00508         }
00509 
00510         byte *ino = (byte *)img->getBasePtr(xp, yp);
00511         byte *outo = (byte *)target.getBasePtr(posX, posY);
00512 
00513         if (color == 0xFFFFFFFF && blendMode == BLEND_NORMAL && _alphaMode == ALPHA_OPAQUE) {
00514             doBlitOpaqueFast(ino, outo, img->w, img->h, target.pitch, inStep, inoStep);
00515         } else if (color == 0xFFFFFFFF && blendMode == BLEND_NORMAL && _alphaMode == ALPHA_BINARY) {
00516             doBlitBinaryFast(ino, outo, img->w, img->h, target.pitch, inStep, inoStep);
00517         } else {
00518             if (blendMode == BLEND_ADDITIVE) {
00519                 doBlitAdditiveBlend(ino, outo, img->w, img->h, target.pitch, inStep, inoStep, color);
00520             } else if (blendMode == BLEND_SUBTRACTIVE) {
00521                 doBlitSubtractiveBlend(ino, outo, img->w, img->h, target.pitch, inStep, inoStep, color);
00522             } else if (blendMode == BLEND_MULTIPLY) {
00523                 doBlitMultiplyBlend(ino, outo, img->w, img->h, target.pitch, inStep, inoStep, color);
00524             } else {
00525                 assert(blendMode == BLEND_NORMAL);
00526                 doBlitAlphaBlend(ino, outo, img->w, img->h, target.pitch, inStep, inoStep, color);
00527             }
00528         }
00529 
00530     }
00531 
00532     retSize.setWidth(img->w);
00533     retSize.setHeight(img->h);
00534 
00535     if (imgScaled) {
00536         imgScaled->setPixels(savedPixels);
00537         imgScaled->free();
00538         delete imgScaled;
00539     }
00540 
00541     return retSize;
00542 }
00543 
00544 Common::Rect TransparentSurface::blitClip(Graphics::Surface &target, Common::Rect clippingArea, int posX, int posY, int flipping, Common::Rect *pPartRect, uint color, int width, int height, TSpriteBlendMode blendMode) {
00545     Common::Rect retSize;
00546     retSize.top = 0;
00547     retSize.left = 0;
00548     retSize.setWidth(0);
00549     retSize.setHeight(0);
00550     // Check if we need to draw anything at all
00551     int ca = (color >> kAModShift) & 0xff;
00552 
00553     if (ca == 0) {
00554         return retSize;
00555     }
00556 
00557     // Create an encapsulating surface for the data
00558     TransparentSurface srcImage(*this, false);
00559     // TODO: Is the data really in the screen format?
00560     if (format.bytesPerPixel != 4) {
00561         warning("TransparentSurface can only blit 32bpp images, but got %d", format.bytesPerPixel * 8);
00562         return retSize;
00563     }
00564 
00565     if (pPartRect) {
00566 
00567         int xOffset = pPartRect->left;
00568         int yOffset = pPartRect->top;
00569 
00570         if (flipping & FLIP_V) {
00571             yOffset = srcImage.h - pPartRect->bottom;
00572         }
00573 
00574         if (flipping & FLIP_H) {
00575             xOffset = srcImage.w - pPartRect->right;
00576         }
00577 
00578         srcImage.pixels = getBasePtr(xOffset, yOffset);
00579         srcImage.w = pPartRect->width();
00580         srcImage.h = pPartRect->height();
00581 
00582         debug(6, "Blit(%d, %d, %d, [%d, %d, %d, %d], %08x, %d, %d)", posX, posY, flipping,
00583             pPartRect->left, pPartRect->top, pPartRect->width(), pPartRect->height(), color, width, height);
00584     } else {
00585 
00586         debug(6, "Blit(%d, %d, %d, [%d, %d, %d, %d], %08x, %d, %d)", posX, posY, flipping, 0, 0,
00587             srcImage.w, srcImage.h, color, width, height);
00588     }
00589 
00590     if (width == -1) {
00591         width = srcImage.w;
00592     }
00593     if (height == -1) {
00594         height = srcImage.h;
00595     }
00596 
00597 #ifdef SCALING_TESTING
00598     // Hardcode scaling to 66% to test scaling
00599     width = width * 2 / 3;
00600     height = height * 2 / 3;
00601 #endif
00602 
00603     Graphics::Surface *img = nullptr;
00604     Graphics::Surface *imgScaled = nullptr;
00605     byte *savedPixels = nullptr;
00606     if ((width != srcImage.w) || (height != srcImage.h)) {
00607         // Scale the image
00608         img = imgScaled = srcImage.scale(width, height);
00609         savedPixels = (byte *)img->getPixels();
00610     } else {
00611         img = &srcImage;
00612     }
00613 
00614     // Handle off-screen clipping
00615     if (posY < clippingArea.top) {
00616         img->h = MAX(0, (int)img->h - (clippingArea.top - posY));
00617         if (!(flipping & FLIP_V))
00618             img->setPixels((byte *)img->getBasePtr(0, clippingArea.top - posY));
00619         posY = clippingArea.top;
00620     }
00621 
00622     if (posX < clippingArea.left) {
00623         img->w = MAX(0, (int)img->w - (clippingArea.left - posX));
00624         if (!(flipping & FLIP_H))
00625             img->setPixels((byte *)img->getBasePtr(clippingArea.left - posX, 0));
00626         posX = clippingArea.left;
00627     }
00628 
00629     if (img->w > clippingArea.right - posX) {
00630         if (flipping & FLIP_H)
00631             img->setPixels((byte *)img->getBasePtr(img->w - clippingArea.right + posX, 0));
00632         img->w = CLIP((int)img->w, 0, (int)MAX((int)clippingArea.right - posX, 0));
00633     }
00634 
00635     if (img->h > clippingArea.bottom - posY) {
00636         if (flipping & FLIP_V)
00637             img->setPixels((byte *)img->getBasePtr(0, img->h - clippingArea.bottom + posY));
00638         img->h = CLIP((int)img->h, 0, (int)MAX((int)clippingArea.bottom - posY, 0));
00639     }
00640 
00641     // Flip surface
00642     if ((img->w > 0) && (img->h > 0)) {
00643         int xp = 0, yp = 0;
00644 
00645         int inStep = 4;
00646         int inoStep = img->pitch;
00647         if (flipping & FLIP_H) {
00648             inStep = -inStep;
00649             xp = img->w - 1;
00650         }
00651 
00652         if (flipping & FLIP_V) {
00653             inoStep = -inoStep;
00654             yp = img->h - 1;
00655         }
00656 
00657         byte *ino = (byte *)img->getBasePtr(xp, yp);
00658         byte *outo = (byte *)target.getBasePtr(posX, posY);
00659 
00660         if (color == 0xFFFFFFFF && blendMode == BLEND_NORMAL && _alphaMode == ALPHA_OPAQUE) {
00661             doBlitOpaqueFast(ino, outo, img->w, img->h, target.pitch, inStep, inoStep);
00662         } else if (color == 0xFFFFFFFF && blendMode == BLEND_NORMAL && _alphaMode == ALPHA_BINARY) {
00663             doBlitBinaryFast(ino, outo, img->w, img->h, target.pitch, inStep, inoStep);
00664         } else {
00665             if (blendMode == BLEND_ADDITIVE) {
00666                 doBlitAdditiveBlend(ino, outo, img->w, img->h, target.pitch, inStep, inoStep, color);
00667             } else if (blendMode == BLEND_SUBTRACTIVE) {
00668                 doBlitSubtractiveBlend(ino, outo, img->w, img->h, target.pitch, inStep, inoStep, color);
00669             } else if (blendMode == BLEND_MULTIPLY) {
00670                 doBlitMultiplyBlend(ino, outo, img->w, img->h, target.pitch, inStep, inoStep, color);
00671             } else {
00672                 assert(blendMode == BLEND_NORMAL);
00673                 doBlitAlphaBlend(ino, outo, img->w, img->h, target.pitch, inStep, inoStep, color);
00674             }
00675         }
00676 
00677     }
00678 
00679     retSize.setWidth(img->w);
00680     retSize.setHeight(img->h);
00681 
00682     if (imgScaled) {
00683         imgScaled->setPixels(savedPixels);
00684         imgScaled->free();
00685         delete imgScaled;
00686     }
00687 
00688     return retSize;
00689 }
00690 
00698 void TransparentSurface::applyColorKey(uint8 rKey, uint8 gKey, uint8 bKey, bool overwriteAlpha) {
00699     assert(format.bytesPerPixel == 4);
00700     for (int i = 0; i < h; i++) {
00701         for (int j = 0; j < w; j++) {
00702             uint32 pix = ((uint32 *)pixels)[i * w + j];
00703             uint8 r, g, b, a;
00704             format.colorToARGB(pix, a, r, g, b);
00705             if (r == rKey && g == gKey && b == bKey) {
00706                 a = 0;
00707                 ((uint32 *)pixels)[i * w + j] = format.ARGBToColor(a, r, g, b);
00708             } else if (overwriteAlpha) {
00709                 a = 255;
00710                 ((uint32 *)pixels)[i * w + j] = format.ARGBToColor(a, r, g, b);
00711             }
00712         }
00713     }
00714 }
00715 
00716 AlphaType TransparentSurface::getAlphaMode() const {
00717     return _alphaMode;
00718 }
00719 
00720 void TransparentSurface::setAlphaMode(AlphaType mode) {
00721     _alphaMode = mode;
00722 }
00723 
00724 
00725 
00726 
00727 
00728 
00729 /*
00730 
00731 The below two functions are adapted from SDL_rotozoom.c,
00732 taken from SDL_gfx-2.0.18.
00733 
00734 Its copyright notice:
00735 
00736 =============================================================================
00737 SDL_rotozoom.c: rotozoomer, zoomer and shrinker for 32bit or 8bit surfaces
00738 
00739 Copyright (C) 2001-2012  Andreas Schiffler
00740 
00741 This software is provided 'as-is', without any express or implied
00742 warranty. In no event will the authors be held liable for any damages
00743 arising from the use of this software.
00744 
00745 Permission is granted to anyone to use this software for any purpose,
00746 including commercial applications, and to alter it and redistribute it
00747 freely, subject to the following restrictions:
00748 
00749 1. The origin of this software must not be misrepresented; you must not
00750 claim that you wrote the original software. If you use this software
00751 in a product, an acknowledgment in the product documentation would be
00752 appreciated but is not required.
00753 
00754 2. Altered source versions must be plainly marked as such, and must not be
00755 misrepresented as being the original software.
00756 
00757 3. This notice may not be removed or altered from any source
00758 distribution.
00759 
00760 Andreas Schiffler -- aschiffler at ferzkopp dot net
00761 =============================================================================
00762 
00763 
00764 The functions have been adapted for different structures and coordinate
00765 systems.
00766 
00767 */
00768 
00769 
00770 
00771 
00772 struct tColorRGBA { byte r; byte g; byte b; byte a; };
00773 
00774 template <TFilteringMode filteringMode>
00775 TransparentSurface *TransparentSurface::rotoscaleT(const TransformStruct &transform) const {
00776 
00777     assert(transform._angle != 0); // This would not be ideal; rotoscale() should never be called in conditional branches where angle = 0 anyway.
00778 
00779     Common::Point newHotspot;
00780     Common::Rect srcRect(0, 0, (int16)w, (int16)h);
00781     Common::Rect rect = TransformTools::newRect(Common::Rect(srcRect), transform, &newHotspot);
00782     Common::Rect dstRect(0, 0, (int16)(rect.right - rect.left), (int16)(rect.bottom - rect.top));
00783 
00784     TransparentSurface *target = new TransparentSurface();
00785     assert(format.bytesPerPixel == 4);
00786 
00787     int srcW = w;
00788     int srcH = h;
00789     int dstW = dstRect.width();
00790     int dstH = dstRect.height();
00791 
00792     target->create((uint16)dstW, (uint16)dstH, this->format);
00793 
00794     if (transform._zoom.x == 0 || transform._zoom.y == 0) {
00795         return target;
00796     }
00797 
00798     uint32 invAngle = 360 - (transform._angle % 360);
00799     float invAngleRad = Common::deg2rad<uint32,float>(invAngle);
00800     float invCos = cos(invAngleRad);
00801     float invSin = sin(invAngleRad);
00802 
00803     int icosx = (int)(invCos * (65536.0f * kDefaultZoomX / transform._zoom.x));
00804     int isinx = (int)(invSin * (65536.0f * kDefaultZoomX / transform._zoom.x));
00805     int icosy = (int)(invCos * (65536.0f * kDefaultZoomY / transform._zoom.y));
00806     int isiny = (int)(invSin * (65536.0f * kDefaultZoomY / transform._zoom.y));
00807 
00808 
00809     bool flipx = false, flipy = false; // TODO: See mirroring comment in RenderTicket ctor
00810 
00811     int xd = (srcRect.left + transform._hotspot.x) << 16;
00812     int yd = (srcRect.top + transform._hotspot.y) << 16;
00813     int cx = newHotspot.x;
00814     int cy = newHotspot.y;
00815 
00816     int ax = -icosx * cx;
00817     int ay = -isiny * cx;
00818     int sw = srcW - 1;
00819     int sh = srcH - 1;
00820 
00821     tColorRGBA *pc = (tColorRGBA*)target->getBasePtr(0, 0);
00822 
00823     for (int y = 0; y < dstH; y++) {
00824         int t = cy - y;
00825         int sdx = ax + (isinx * t) + xd;
00826         int sdy = ay - (icosy * t) + yd;
00827         for (int x = 0; x < dstW; x++) {
00828             int dx = (sdx >> 16);
00829             int dy = (sdy >> 16);
00830             if (flipx) {
00831                 dx = sw - dx;
00832             }
00833             if (flipy) {
00834                 dy = sh - dy;
00835             }
00836 
00837             if (filteringMode == FILTER_BILINEAR) {
00838                 if ((dx > -1) && (dy > -1) && (dx < sw) && (dy < sh)) {
00839                     const tColorRGBA *sp = (const tColorRGBA *)getBasePtr(dx, dy);
00840                     tColorRGBA c00, c01, c10, c11, cswap;
00841                     c00 = *sp;
00842                     sp += 1;
00843                     c01 = *sp;
00844                     sp += (this->pitch / 4);
00845                     c11 = *sp;
00846                     sp -= 1;
00847                     c10 = *sp;
00848                     if (flipx) {
00849                         cswap = c00; c00=c01; c01=cswap;
00850                         cswap = c10; c10=c11; c11=cswap;
00851                     }
00852                     if (flipy) {
00853                         cswap = c00; c00=c10; c10=cswap;
00854                         cswap = c01; c01=c11; c11=cswap;
00855                     }
00856                     /*
00857                     * Interpolate colors
00858                     */
00859                     int ex = (sdx & 0xffff);
00860                     int ey = (sdy & 0xffff);
00861                     int t1, t2;
00862                     t1 = ((((c01.r - c00.r) * ex) >> 16) + c00.r) & 0xff;
00863                     t2 = ((((c11.r - c10.r) * ex) >> 16) + c10.r) & 0xff;
00864                     pc->r = (((t2 - t1) * ey) >> 16) + t1;
00865                     t1 = ((((c01.g - c00.g) * ex) >> 16) + c00.g) & 0xff;
00866                     t2 = ((((c11.g - c10.g) * ex) >> 16) + c10.g) & 0xff;
00867                     pc->g = (((t2 - t1) * ey) >> 16) + t1;
00868                     t1 = ((((c01.b - c00.b) * ex) >> 16) + c00.b) & 0xff;
00869                     t2 = ((((c11.b - c10.b) * ex) >> 16) + c10.b) & 0xff;
00870                     pc->b = (((t2 - t1) * ey) >> 16) + t1;
00871                     t1 = ((((c01.a - c00.a) * ex) >> 16) + c00.a) & 0xff;
00872                     t2 = ((((c11.a - c10.a) * ex) >> 16) + c10.a) & 0xff;
00873                     pc->a = (((t2 - t1) * ey) >> 16) + t1;
00874                 }
00875             } else {
00876                 if ((dx >= 0) && (dy >= 0) && (dx < srcW) && (dy < srcH)) {
00877                     const tColorRGBA *sp = (const tColorRGBA *)getBasePtr(dx, dy);
00878                     *pc = *sp;
00879                 }
00880             }
00881             sdx += icosx;
00882             sdy += isiny;
00883             pc++;
00884         }
00885     }
00886     return target;
00887 }
00888 
00889 template <TFilteringMode filteringMode>
00890 TransparentSurface *TransparentSurface::scaleT(uint16 newWidth, uint16 newHeight) const {
00891 
00892     TransparentSurface *target = new TransparentSurface();
00893 
00894     int srcW = w;
00895     int srcH = h;
00896     int dstW = newWidth;
00897     int dstH = newHeight;
00898 
00899     target->create((uint16)dstW, (uint16)dstH, format);
00900 
00901     if (filteringMode == FILTER_BILINEAR) {
00902         assert(format.bytesPerPixel == 4);
00903 
00904         bool flipx = false, flipy = false; // TODO: See mirroring comment in RenderTicket ctor
00905 
00906 
00907         int *sax = new int[dstW + 1];
00908         int *say = new int[dstH + 1];
00909         assert(sax && say);
00910 
00911         /*
00912         * Precalculate row increments
00913         */
00914         int spixelw = (srcW - 1);
00915         int spixelh = (srcH - 1);
00916         int sx = (int)(65536.0f * (float) spixelw / (float) (dstW - 1));
00917         int sy = (int)(65536.0f * (float) spixelh / (float) (dstH - 1));
00918 
00919         /* Maximum scaled source size */
00920         int ssx = (srcW << 16) - 1;
00921         int ssy = (srcH << 16) - 1;
00922 
00923         /* Precalculate horizontal row increments */
00924         int csx = 0;
00925         int *csax = sax;
00926         for (int x = 0; x <= dstW; x++) {
00927             *csax = csx;
00928             csax++;
00929             csx += sx;
00930 
00931             /* Guard from overflows */
00932             if (csx > ssx) {
00933                 csx = ssx;
00934             }
00935         }
00936 
00937         /* Precalculate vertical row increments */
00938         int csy = 0;
00939         int *csay = say;
00940         for (int y = 0; y <= dstH; y++) {
00941             *csay = csy;
00942             csay++;
00943             csy += sy;
00944 
00945             /* Guard from overflows */
00946             if (csy > ssy) {
00947                 csy = ssy;
00948             }
00949         }
00950 
00951         const tColorRGBA *sp = (const tColorRGBA *) getBasePtr(0, 0);
00952         tColorRGBA *dp = (tColorRGBA *) target->getBasePtr(0, 0);
00953         int spixelgap = srcW;
00954 
00955         if (flipx) {
00956             sp += spixelw;
00957         }
00958         if (flipy) {
00959             sp += spixelgap * spixelh;
00960         }
00961 
00962         csay = say;
00963         for (int y = 0; y < dstH; y++) {
00964             const tColorRGBA *csp = sp;
00965             csax = sax;
00966             for (int x = 0; x < dstW; x++) {
00967                 /*
00968                 * Setup color source pointers
00969                 */
00970                 int ex = (*csax & 0xffff);
00971                 int ey = (*csay & 0xffff);
00972                 int cx = (*csax >> 16);
00973                 int cy = (*csay >> 16);
00974 
00975                 const tColorRGBA *c00, *c01, *c10, *c11;
00976                 c00 = sp;
00977                 c01 = sp;
00978                 c10 = sp;
00979                 if (cy < spixelh) {
00980                     if (flipy) {
00981                         c10 -= spixelgap;
00982                     } else {
00983                         c10 += spixelgap;
00984                     }
00985                 }
00986                 c11 = c10;
00987                 if (cx < spixelw) {
00988                     if (flipx) {
00989                         c01--;
00990                         c11--;
00991                     } else {
00992                         c01++;
00993                         c11++;
00994                     }
00995                 }
00996 
00997                 /*
00998                 * Draw and interpolate colors
00999                 */
01000                 int t1, t2;
01001                 t1 = ((((c01->r - c00->r) * ex) >> 16) + c00->r) & 0xff;
01002                 t2 = ((((c11->r - c10->r) * ex) >> 16) + c10->r) & 0xff;
01003                 dp->r = (((t2 - t1) * ey) >> 16) + t1;
01004                 t1 = ((((c01->g - c00->g) * ex) >> 16) + c00->g) & 0xff;
01005                 t2 = ((((c11->g - c10->g) * ex) >> 16) + c10->g) & 0xff;
01006                 dp->g = (((t2 - t1) * ey) >> 16) + t1;
01007                 t1 = ((((c01->b - c00->b) * ex) >> 16) + c00->b) & 0xff;
01008                 t2 = ((((c11->b - c10->b) * ex) >> 16) + c10->b) & 0xff;
01009                 dp->b = (((t2 - t1) * ey) >> 16) + t1;
01010                 t1 = ((((c01->a - c00->a) * ex) >> 16) + c00->a) & 0xff;
01011                 t2 = ((((c11->a - c10->a) * ex) >> 16) + c10->a) & 0xff;
01012                 dp->a = (((t2 - t1) * ey) >> 16) + t1;
01013 
01014                 /*
01015                 * Advance source pointer x
01016                 */
01017                 int *salastx = csax;
01018                 csax++;
01019                 int sstepx = (*csax >> 16) - (*salastx >> 16);
01020                 if (flipx) {
01021                     sp -= sstepx;
01022                 } else {
01023                     sp += sstepx;
01024                 }
01025 
01026                 /*
01027                 * Advance destination pointer x
01028                 */
01029                 dp++;
01030             }
01031             /*
01032             * Advance source pointer y
01033             */
01034             int *salasty = csay;
01035             csay++;
01036             int sstepy = (*csay >> 16) - (*salasty >> 16);
01037             sstepy *= spixelgap;
01038             if (flipy) {
01039                 sp = csp - sstepy;
01040             } else {
01041                 sp = csp + sstepy;
01042             }
01043         }
01044 
01045         delete[] sax;
01046         delete[] say;
01047 
01048     } else {
01049         int *scaleCacheX = new int[dstW];
01050         for (int x = 0; x < dstW; x++) {
01051             scaleCacheX[x] = (x * srcW) / dstW;
01052         }
01053 
01054         switch (format.bytesPerPixel) {
01055         case 1:
01056             scaleNN<uint8>(scaleCacheX, target);
01057             break;
01058         case 2:
01059             scaleNN<uint16>(scaleCacheX, target);
01060             break;
01061         case 4:
01062             scaleNN<uint32>(scaleCacheX, target);
01063             break;
01064         default:
01065             error("Can only scale 8bpp, 16bpp, and 32bpp");
01066         }
01067 
01068         delete[] scaleCacheX;
01069     }
01070 
01071     return target;
01072 }
01073 
01074 TransparentSurface *TransparentSurface::convertTo(const PixelFormat &dstFormat, const byte *palette) const {
01075     assert(pixels);
01076 
01077     TransparentSurface *surface = new TransparentSurface();
01078 
01079     // If the target format is the same, just copy
01080     if (format == dstFormat) {
01081         surface->copyFrom(*this);
01082         return surface;
01083     }
01084 
01085     if (format.bytesPerPixel == 0 || format.bytesPerPixel > 4)
01086         error("Surface::convertTo(): Can only convert from 1Bpp, 2Bpp, 3Bpp, and 4Bpp");
01087 
01088     if (dstFormat.bytesPerPixel != 2 && dstFormat.bytesPerPixel != 4)
01089         error("Surface::convertTo(): Can only convert to 2Bpp and 4Bpp");
01090 
01091     surface->create(w, h, dstFormat);
01092 
01093     if (format.bytesPerPixel == 1) {
01094         // Converting from paletted to high color
01095         assert(palette);
01096 
01097         for (int y = 0; y < h; y++) {
01098             const byte *srcRow = (const byte *)getBasePtr(0, y);
01099             byte *dstRow = (byte *)surface->getBasePtr(0, y);
01100 
01101             for (int x = 0; x < w; x++) {
01102                 byte index = *srcRow++;
01103                 byte r = palette[index * 3];
01104                 byte g = palette[index * 3 + 1];
01105                 byte b = palette[index * 3 + 2];
01106 
01107                 uint32 color = dstFormat.RGBToColor(r, g, b);
01108 
01109                 if (dstFormat.bytesPerPixel == 2)
01110                     *((uint16 *)dstRow) = color;
01111                 else
01112                     *((uint32 *)dstRow) = color;
01113 
01114                 dstRow += dstFormat.bytesPerPixel;
01115             }
01116         }
01117     } else {
01118         // Converting from high color to high color
01119         for (int y = 0; y < h; y++) {
01120             const byte *srcRow = (const byte *)getBasePtr(0, y);
01121             byte *dstRow = (byte *)surface->getBasePtr(0, y);
01122 
01123             for (int x = 0; x < w; x++) {
01124                 uint32 srcColor;
01125                 if (format.bytesPerPixel == 2)
01126                     srcColor = READ_UINT16(srcRow);
01127                 else if (format.bytesPerPixel == 3)
01128                     srcColor = READ_UINT24(srcRow);
01129                 else
01130                     srcColor = READ_UINT32(srcRow);
01131 
01132                 srcRow += format.bytesPerPixel;
01133 
01134                 // Convert that color to the new format
01135                 byte r, g, b, a;
01136                 format.colorToARGB(srcColor, a, r, g, b);
01137                 uint32 color = dstFormat.ARGBToColor(a, r, g, b);
01138 
01139                 if (dstFormat.bytesPerPixel == 2)
01140                     *((uint16 *)dstRow) = color;
01141                 else
01142                     *((uint32 *)dstRow) = color;
01143 
01144                 dstRow += dstFormat.bytesPerPixel;
01145             }
01146         }
01147     }
01148 
01149     return surface;
01150 }
01151 
01152 template <typename Size>
01153 void TransparentSurface::scaleNN(int *scaleCacheX, TransparentSurface *target) const {
01154     for (int y = 0; y < target->h; y++) {
01155         Size *destP = (Size *)target->getBasePtr(0, y);
01156         const Size *srcP = (const Size *)getBasePtr(0, (y * h) / target->h);
01157         for (int x = 0; x < target->w; x++) {
01158             *destP++ = srcP[scaleCacheX[x]];
01159         }
01160     }
01161 }
01162 
01163 template TransparentSurface *TransparentSurface::rotoscaleT<FILTER_NEAREST>(const TransformStruct &transform) const;
01164 template TransparentSurface *TransparentSurface::rotoscaleT<FILTER_BILINEAR>(const TransformStruct &transform) const;
01165 template TransparentSurface *TransparentSurface::scaleT<FILTER_NEAREST>(uint16 newWidth, uint16 newHeight) const;
01166 template TransparentSurface *TransparentSurface::scaleT<FILTER_BILINEAR>(uint16 newWidth, uint16 newHeight) const;
01167 
01168 template void TransparentSurface::scaleNN<uint8>(int *scaleCacheX, TransparentSurface *target) const;
01169 template void TransparentSurface::scaleNN<uint16>(int *scaleCacheX, TransparentSurface *target) const;
01170 template void TransparentSurface::scaleNN<uint32>(int *scaleCacheX, TransparentSurface *target) const;
01171 
01172 TransparentSurface *TransparentSurface::rotoscale(const TransformStruct &transform) const {
01173     return rotoscaleT<FILTER_BILINEAR>(transform);
01174 }
01175 
01176 TransparentSurface *TransparentSurface::scale(uint16 newWidth, uint16 newHeight) const {
01177     return scaleT<FILTER_NEAREST>(newWidth, newHeight);
01178 }
01179 
01180 } // End of namespace Graphics


Generated on Sat Feb 23 2019 05:01:19 for ResidualVM by doxygen 1.7.1
curved edge   curved edge