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


Generated on Sat Aug 17 2019 05:00:44 for ResidualVM by doxygen 1.7.1
curved edge   curved edge