/* 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