/* ScummVM - Graphic Adventure Engine * * ScummVM is the legal property of its developers, whose names * are too numerous to list here. Please refer to the COPYRIGHT * file distributed with this source distribution. * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * */ #include "ags/lib/allegro/color.h" #include "ags/lib/allegro/surface.h" #include "ags/globals.h" namespace AGS3 { template void BITMAP::drawInnerGeneric(DrawInnerArgs &args) { const int xDir = args.horizFlip ? -1 : 1; byte rSrc, gSrc, bSrc, aSrc; byte rDest = 0, gDest = 0, bDest = 0, aDest = 0; // Instead of skipping pixels outside our boundary here, we just clip // our area instead. int xCtrStart = 0, xCtrBppStart = 0, xCtrWidth = args.dstRect.width(); if (args.xStart + xCtrWidth > args.destArea.w) { // Clip the right xCtrWidth = args.destArea.w - args.xStart; } if (args.xStart < 0) { // Clip the left xCtrStart = -args.xStart; xCtrBppStart = xCtrStart * SrcBytesPerPixel; args.xStart = 0; } int destY = args.yStart, yCtr = 0, srcYCtr = 0, scaleYCtr = 0, yCtrHeight = args.dstRect.height(); if (args.yStart < 0) { // Clip the top yCtr = -args.yStart; destY = 0; if (Scale) { scaleYCtr = yCtr * args.scaleY; srcYCtr = scaleYCtr / BITMAP::SCALE_THRESHOLD; } } if (args.yStart + yCtrHeight > args.destArea.h) { // Clip the bottom yCtrHeight = args.destArea.h - args.yStart; } byte *destP = (byte *)args.destArea.getBasePtr(0, destY); const byte *srcP = (const byte *)args.src.getBasePtr( args.horizFlip ? args.srcArea.right - 1 : args.srcArea.left, args.vertFlip ? args.srcArea.bottom - 1 - yCtr : args.srcArea.top + yCtr); for (; yCtr < yCtrHeight; ++destY, ++yCtr, scaleYCtr += args.scaleY) { if (Scale) { int newSrcYCtr = scaleYCtr / BITMAP::SCALE_THRESHOLD; if (srcYCtr != newSrcYCtr) { int diffSrcYCtr = newSrcYCtr - srcYCtr; srcP += args.src.pitch * diffSrcYCtr; srcYCtr = newSrcYCtr; } } // Loop through the pixels of the row for (int destX = args.xStart, xCtr = xCtrStart, xCtrBpp = xCtrBppStart, scaleXCtr = xCtr * args.scaleX; xCtr < xCtrWidth; ++destX, ++xCtr, xCtrBpp += SrcBytesPerPixel, scaleXCtr += args.scaleX) { const byte *srcVal = srcP + xDir * xCtrBpp; if (Scale) { srcVal = srcP + (scaleXCtr / BITMAP::SCALE_THRESHOLD) * SrcBytesPerPixel; } uint32 srcCol = getColor(srcVal, SrcBytesPerPixel); // Check if this is a transparent color we should skip if (args.skipTrans && ((srcCol & args.alphaMask) == args.transColor)) continue; byte *destVal = (byte *)&destP[destX * DestBytesPerPixel]; // When blitting to the same format we can just copy the color if (DestBytesPerPixel == 1) { *destVal = srcCol; continue; } else if ((DestBytesPerPixel == SrcBytesPerPixel) && args.srcAlpha == -1) { if (DestBytesPerPixel == 4) *(uint32 *)destVal = srcCol; else *(uint16 *)destVal = srcCol; continue; } // We need the rgb values to do blending and/or convert between formats if (SrcBytesPerPixel == 1) { const RGB &rgb = args.palette[srcCol]; aSrc = 0xff; rSrc = rgb.r; gSrc = rgb.g; bSrc = rgb.b; } else { if (SrcBytesPerPixel == 4) { aSrc = srcCol >> 24; rSrc = (srcCol >> 16) & 0xff; gSrc = (srcCol >> 8) & 0xff; bSrc = srcCol & 0xff; } else { // SrcBytesPerPixel == 2 aSrc = 0xff; rSrc = (srcCol >> 11) & 0x1f; rSrc = (rSrc << 3) | (rSrc >> 2); gSrc = (srcCol >> 5) & 0x3f; gSrc = (gSrc << 2) | (gSrc >> 4); bSrc = srcCol & 0x1f; bSrc = (bSrc << 3) | (bSrc >> 2); } //src.format.colorToARGB(srcCol, aSrc, rSrc, gSrc, bSrc); } if (args.srcAlpha == -1) { // This means we don't use blending. aDest = aSrc; rDest = rSrc; gDest = gSrc; bDest = bSrc; } else { if (args.useTint) { rDest = rSrc; gDest = gSrc; bDest = bSrc; aDest = aSrc; rSrc = args.tintRed; gSrc = args.tintGreen; bSrc = args.tintBlue; aSrc = args.srcAlpha; } else { uint32 destCol = getColor(destVal, DestBytesPerPixel); if (DestBytesPerPixel == 1) { const RGB &rgb = args.palette[destCol]; aDest = 0xff; rDest = rgb.r; gDest = rgb.g; bDest = rgb.b; } else { if (DestBytesPerPixel == 4) { aDest = destCol >> 24; rDest = (destCol >> 16) & 0xff; gDest = (destCol >> 8) & 0xff; bDest = destCol & 0xff; } else { // DestBytesPerPixel == 2 aDest = 0xff; rDest = (destCol >> 11) & 0x1f; rDest = (rDest << 3) | (rDest >> 2); gDest = (destCol >> 5) & 0x3f; gDest = (gDest << 2) | (gDest >> 4); bDest = destCol & 0x1f; bDest = (bDest << 3) | (bDest >> 2); } //src.format.colorToARGB(srcCol, aSrc, rSrc, gSrc, bSrc); } } blendPixel(aSrc, rSrc, gSrc, bSrc, aDest, rDest, gDest, bDest, args.srcAlpha, args.useTint, destVal); } uint32 pixel;// = format.ARGBToColor(aDest, rDest, gDest, bDest); if (DestBytesPerPixel == 4) { pixel = (aDest << 24) | (rDest << 16) | (gDest << 8) | (bDest); *(uint32 *)destVal = pixel; } else { pixel = ((rDest >> 3) << 11) | ((gDest >> 2) << 5) | (bDest >> 3); *(uint16 *)destVal = pixel; } } destP += args.destArea.pitch; if (!Scale) srcP += args.vertFlip ? -args.src.pitch : args.src.pitch; } } template void BITMAP::drawGeneric(DrawInnerArgs &args) { if (args.sameFormat) { switch (format.bytesPerPixel) { case 1: drawInnerGeneric<1, 1, Scale>(args); break; case 2: drawInnerGeneric<2, 2, Scale>(args); break; case 4: drawInnerGeneric<4, 4, Scale>(args); break; } } else if (format.bytesPerPixel == 4 && args.src.format.bytesPerPixel == 2) { drawInnerGeneric<4, 2, Scale>(args); } else if (format.bytesPerPixel == 2 && args.src.format.bytesPerPixel == 4) { drawInnerGeneric<2, 4, Scale>(args); } } template void BITMAP::drawGeneric(DrawInnerArgs &); template void BITMAP::drawGeneric(DrawInnerArgs &); template void BITMAP::drawInnerGeneric<4, 4, false>(DrawInnerArgs &); template void BITMAP::drawInnerGeneric<4, 4, true>(DrawInnerArgs &); template void BITMAP::drawInnerGeneric<4, 2, false>(DrawInnerArgs &); template void BITMAP::drawInnerGeneric<4, 2, true>(DrawInnerArgs &); template void BITMAP::drawInnerGeneric<2, 4, false>(DrawInnerArgs &); template void BITMAP::drawInnerGeneric<2, 4, true>(DrawInnerArgs &); template void BITMAP::drawInnerGeneric<4, 1, false>(DrawInnerArgs &); template void BITMAP::drawInnerGeneric<4, 1, true>(DrawInnerArgs &); template void BITMAP::drawInnerGeneric<2, 1, false>(DrawInnerArgs &); template void BITMAP::drawInnerGeneric<2, 1, true>(DrawInnerArgs &); } // end of namespace AGS3