Files
scummvm-cursorfix/engines/scumm/he/wizwarp_he.cpp
2026-02-02 04:50:13 +01:00

1254 lines
36 KiB
C++

/* 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 <http://www.gnu.org/licenses/>.
*
*/
#ifdef ENABLE_HE
#include "common/system.h"
#include "scumm/he/intern_he.h"
#include "scumm/he/wiz_he.h"
namespace Scumm {
#define WARP_FRAC_SIZE (_vm->_game.heversion > 98 ? 20 : 16)
#define WARP_FRAC_VALUE (1 << (WARP_FRAC_SIZE))
#define WARP_TEXTURE_LIMIT (1 << (31 - (WARP_FRAC_SIZE)))
#define WARP_TO_FRAC(_x_) ((_x_) << (WARP_FRAC_SIZE))
#define WARP_FROM_FRAC(_x_) ((_x_) >> (WARP_FRAC_SIZE))
bool Wiz::warpDrawWiz(int image, int state, int polygon, int32 flags, int transparentColor, WizSimpleBitmap *optionalDestBitmap, const WizRawPixel *optionalColorConversionTable, int shadowImage) {
const byte *xmapColorTable;
int polyIndex;
// Parameters check...
for (polyIndex = 0; polyIndex < ARRAYSIZE(_polygons); polyIndex++) {
if (_polygons[polyIndex].id == polygon) {
break;
}
}
if (ARRAYSIZE(_polygons) <= polyIndex) {
error("Wiz::warpDrawWiz(): Polygon %d not defined", polygon);
}
if (_polygons[polyIndex].numPoints != 5) {
error("Wiz::warpDrawWiz(): Invalid point count");
}
if (shadowImage) {
xmapColorTable = getColorMixBlockPtrForWiz(shadowImage);
if (xmapColorTable) {
xmapColorTable += _vm->_resourceHeaderSize;
}
} else {
xmapColorTable = nullptr;
}
// Call the actual warping primitive...
WarpWizPoint polypoints[5];
for (int i = 0; i < 5; i++) {
WarpWizPoint tmp(_polygons[polyIndex].points[i]);
polypoints[i] = tmp;
}
return warpDrawWizTo4Points(
image, state, polypoints, flags, transparentColor,
nullptr, optionalDestBitmap, optionalColorConversionTable, xmapColorTable);
}
bool Wiz::warpDrawWizTo4Points(int image, int state, const WarpWizPoint *dstPoints, int32 flags, int transparentColor, const Common::Rect *optionalClipRect, WizSimpleBitmap *optionalDestBitmap, const WizRawPixel *optionalColorConversionTable, const byte *colorMixTable) {
WizSimpleBitmap dstBitmap, srcBitmap;
bool rValue;
Common::Rect updateRect;
int x, y;
WarpWizPoint srcPoints[4];
byte *ptr;
// Set the optional remap table up to the default if one isn't specified...
if (!optionalColorConversionTable && _uses16BitColor) {
optionalColorConversionTable = (WizRawPixel *)_vm->getHEPaletteSlot(1);
}
// Decompress the wiz into a WizSimpleBitmap... (Always, if using a remap table)...
if ((getWizCompressionType(image, state) != kWCTNone) ||
(optionalColorConversionTable != nullptr) || (flags & (kWRFHFlip | kWRFVFlip | kWRFRemap))) {
srcBitmap.bufferPtr = drawAWizPrim(image, state, 0, 0, 0, 0, 0, 0, kWRFAlloc | flags, 0, optionalColorConversionTable);
if (!srcBitmap.bufferPtr()) {
return false;
}
} else {
ptr = (byte *)getWizStateDataPrim(image, state);
if (!ptr)
error("Wiz::warpDrawWizTo4Points(): Image %d missing data", image);
// Map the srcBitmap to the Wiz data...
srcBitmap.bufferPtr = WizPxShrdBuffer(ptr + _vm->_resourceHeaderSize, false);
}
// Fill in the dest bitmap structure...
if (optionalDestBitmap) {
dstBitmap = *optionalDestBitmap;
} else {
VirtScreen *pvs = &_vm->_virtscr[kMainVirtScreen];
dstBitmap.bitmapWidth = pvs->w;
dstBitmap.bitmapHeight = pvs->h;
if (flags & kWRFForeground) {
dstBitmap.bufferPtr = WizPxShrdBuffer(pvs->getPixels(0, pvs->topline), false);
} else {
dstBitmap.bufferPtr = WizPxShrdBuffer(pvs->getBackPixels(0, pvs->topline), false);
}
if (!dstBitmap.bufferPtr()) {
error("Wiz::warpDrawWizTo4Points(): Missing drawing buffer?");
}
dstBitmap.bufferPtr += (pvs->xstart * (_uses16BitColor ? 2 : 1));
}
// Find the bounding rect and double check the coords...
updateRect.left = 12345;
updateRect.top = 12345;
updateRect.right = -12345;
updateRect.bottom = -12345;
for (int i = 0; i < 4; i++) {
x = dstPoints[i].x;
y = dstPoints[i].y;
updateRect.left = MIN<int16>(updateRect.left, x);
updateRect.top = MIN<int16>(updateRect.top, y);
updateRect.right = MAX<int16>(updateRect.right, x);
updateRect.bottom = MAX<int16>(updateRect.bottom, y);
}
updateRect.left = MAX<int16>(0, MIN<int16>((dstBitmap.bitmapWidth - 1), updateRect.left));
updateRect.top = MAX<int16>(0, MIN<int16>((dstBitmap.bitmapHeight - 1), updateRect.top));
updateRect.right = MAX<int16>(0, MIN<int16>((dstBitmap.bitmapWidth - 1), updateRect.right));
updateRect.bottom = MAX<int16>(0, MIN<int16>((dstBitmap.bitmapHeight - 1), updateRect.bottom));
getWizImageDim(image, state, srcBitmap.bitmapWidth, srcBitmap.bitmapHeight);
srcPoints[0].x = 0;
srcPoints[0].y = 0;
srcPoints[1].x = srcBitmap.bitmapWidth - 1;
srcPoints[1].y = 0;
srcPoints[2].x = srcBitmap.bitmapWidth - 1;
srcPoints[2].y = srcBitmap.bitmapHeight - 1;
srcPoints[3].x = 0;
srcPoints[3].y = srcBitmap.bitmapHeight - 1;
// Call the warping primitive...
if (_vm->_game.heversion >= 95 && colorMixTable) {
rValue = warpNPt2NPtClippedWarpMixColors(
&dstBitmap, dstPoints, &srcBitmap, srcPoints, 4, transparentColor,
optionalClipRect, colorMixTable);
} else {
if (_vm->_game.heversion >= 99) { // This shouldn't be a HE99 branch, but some later HE99 executables do this...
rValue = warpNPt2NPtWarpCORE(
&dstBitmap, dstPoints, &srcBitmap, srcPoints,
4, transparentColor, optionalClipRect, flags);
} else {
if (optionalClipRect) {
rValue = warpNPt2NPtClippedWarp(
&dstBitmap, dstPoints, &srcBitmap, srcPoints, 4, transparentColor,
optionalClipRect);
} else {
rValue = warpNPt2NPtNonClippedWarp(
&dstBitmap, dstPoints, &srcBitmap, srcPoints, 4, transparentColor);
}
}
}
// Update the screen? (If not writing to another bitmap...)
if (rValue && !optionalDestBitmap) {
if (!(flags & kWRFForeground)) {
_vm->backgroundToForegroundBlit(updateRect);
} else {
++updateRect.bottom;
_vm->markRectAsDirty(kMainVirtScreen, updateRect);
}
}
// Clean up...
srcBitmap.bufferPtr = WizPxShrdBuffer();
return rValue;
}
WarpWizOneSpanTable *Wiz::warpCreateSpanTable(int spanCount) {
WarpWizOneSpanTable *spanTable;
WarpWizOneSpan *spanPtr;
int counter;
spanTable = (WarpWizOneSpanTable *)malloc(sizeof(WarpWizOneSpanTable));
if (!spanTable) {
return nullptr;
}
// Clear spanTable structure
spanTable->dstMinPt = WarpWizPoint();
spanTable->dstMaxPt = WarpWizPoint();
spanTable->srcMinPt = WarpWizPoint();
spanTable->srcMaxPt = WarpWizPoint();
spanTable->drawSpans = nullptr;
spanTable->spans = nullptr;
spanTable->drawSpanCount = 0;
spanTable->spanCount = 0;
spanTable->spanCount = spanCount;
spanTable->spans = (WarpWizOneSpan *)malloc(spanCount * sizeof(WarpWizOneSpan));
if (!spanTable->spans) {
warpDestroySpanTable(spanTable);
return nullptr;
}
// Clear spanTable spans structure
for (counter = 0; counter < spanCount; counter++) {
spanTable->spans[counter].dstLeft = 0;
spanTable->spans[counter].dstRight = 0;
spanTable->spans[counter].srcLeft = WarpWizPoint();
spanTable->spans[counter].srcRight = WarpWizPoint();
}
spanPtr = spanTable->spans;
for (counter = 0; counter < spanCount; counter++) {
spanPtr->dstLeft = 0x7FFFFFFF;
spanPtr->dstRight = (-0x7FFFFFFF - 1);
spanPtr++;
}
spanTable->drawSpans = (WarpWizOneDrawSpan *)malloc(spanCount * sizeof(WarpWizOneDrawSpan));
if (!spanTable->drawSpans) {
warpDestroySpanTable(spanTable);
return nullptr;
}
memset(spanTable->drawSpans, 0, spanCount * sizeof(WarpWizOneDrawSpan));
return spanTable;
}
void Wiz::warpDestroySpanTable(WarpWizOneSpanTable *spanTable) {
if (spanTable->drawSpans) {
free(spanTable->drawSpans);
spanTable->drawSpans = nullptr;
}
if (spanTable->spans) {
free(spanTable->spans);
spanTable->spans = nullptr;
}
free(spanTable);
spanTable = nullptr;
}
WarpWizOneSpanTable *Wiz::warpBuildSpanTable(WizSimpleBitmap *dstBitmap, const WizSimpleBitmap *srcBitmap, const WarpWizPoint *dstPts, const WarpWizPoint *srcPts, int npoints, const Common::Rect *clipRectPtr) {
int offset, dw, nonClippedWidth, cl, cr, cy, dl, cw;
WarpWizPoint srcPt, dstPt, dstMinPt, dstMaxPt, srcMinPt, srcMaxPt, clippedPt;
WarpWizOneDrawSpan *drawSpan;
Common::Rect clippingRect;
WarpWizOneSpanTable *st;
WarpWizOneSpan *span;
bool ignoreAll;
// Setup the clipping rect
clippingRect.left = 0;
clippingRect.top = 0;
clippingRect.right = dstBitmap->bitmapWidth - 1;
clippingRect.bottom = dstBitmap->bitmapHeight - 1;
ignoreAll = false;
if (clipRectPtr) {
if (!findRectOverlap(&clippingRect, clipRectPtr)) {
ignoreAll = true;
}
}
// Find the span table fun parts...
warpFindMinMaxpoints(&dstMinPt, &dstMaxPt, dstPts, npoints);
warpFindMinMaxpoints(&srcMinPt, &srcMaxPt, srcPts, npoints);
st = warpCreateSpanTable((dstMaxPt.y - dstMinPt.y) + 1);
if (!st) {
return nullptr;
}
st->dstMinPt = dstMinPt;
st->dstMaxPt = dstMaxPt;
st->srcMinPt = srcMinPt;
st->srcMaxPt = srcMaxPt;
dstPt = *dstPts;
srcPt = *srcPts;
// Scan convert the polygon...
for (int i = 1; i < npoints; i++) {
warpFillSpanWithLine(st, dstPts, dstPts + 1, srcPts, srcPts + 1);
dstPts++;
srcPts++;
}
warpFillSpanWithLine(st, dstPts, &dstPt, srcPts, &srcPt);
// Build the draw span table...
drawSpan = st->drawSpans;
dw = dstBitmap->bitmapWidth;
span = st->spans;
offset = st->dstMinPt.y * dw;
st->drawSpanCount = 0;
cy = st->dstMinPt.y;
if (ignoreAll) {
return st;
}
for (int i = st->spanCount; --i >= 0; ++cy, ++span, offset += dw) {
// Clip vertical?
if ((cy < clippingRect.top) || (cy > clippingRect.bottom)) {
continue;
}
// Clip horizontal?
cl = MAX<int>(clippingRect.left, span->dstLeft);
cr = MIN<int>(clippingRect.right, span->dstRight);
if ((cw = (cr - cl + 1)) <= 0) {
continue;
}
// Calc the step values...
nonClippedWidth = (span->dstRight) - (span->dstLeft) + 1;
drawSpan->xSrcStep = WARP_TO_FRAC((span->srcRight.x - span->srcLeft.x)) / nonClippedWidth;
drawSpan->ySrcStep = WARP_TO_FRAC((span->srcRight.y - span->srcLeft.y)) / nonClippedWidth;
// Calc the clipped values...
drawSpan->dstOffset = offset + cl;
drawSpan->dstWidth = cw;
drawSpan->xSrcOffset = WARP_TO_FRAC(span->srcLeft.x);
drawSpan->ySrcOffset = WARP_TO_FRAC(span->srcLeft.y);
if ((dl = (cl - span->dstLeft)) != 0) {
drawSpan->xSrcOffset += (dl * drawSpan->xSrcStep);
drawSpan->ySrcOffset += (dl * drawSpan->ySrcStep);
}
st->drawSpanCount++;
drawSpan++;
}
return st;
}
void Wiz::warpFindMinMaxpoints(WarpWizPoint *minPtr, WarpWizPoint *maxPtr, const WarpWizPoint *points, int npoints) {
WarpWizPoint minPt, maxPt, pt;
// Find the limits...
maxPt.x = (-0x7FFFFFFF - 1);
maxPt.y = (-0x7FFFFFFF - 1);
minPt.x = 0x7FFFFFFF;
minPt.y = 0x7FFFFFFF;
for (int i = 0; i < npoints; i++) {
pt = *points++;
if (pt.x < minPt.x) {
minPt.x = pt.x;
}
if (pt.y < minPt.y) {
minPt.y = pt.y;
}
if (pt.x > maxPt.x) {
maxPt.x = pt.x;
}
if (pt.y > maxPt.y) {
maxPt.y = pt.y;
}
}
*minPtr = minPt;
*maxPtr = maxPt;
}
void Wiz::warpProcessDrawSpansA(WizSimpleBitmap *dstBitmap, const WizSimpleBitmap *srcBitmap, const WarpWizOneDrawSpan *drawSpans, int count) {
int xStep, yStep, sw, xOffset, yOffset;
const WizRawPixel8 *src8;
const WizRawPixel16 *src16;
WizRawPixel8 *dst8 = (WizRawPixel8 *)dstBitmap->bufferPtr();
WizRawPixel16 *dst16 = (WizRawPixel16 *)dstBitmap->bufferPtr();
sw = srcBitmap->bitmapWidth;
src8 = (WizRawPixel8 *)srcBitmap->bufferPtr();
src16 = (WizRawPixel16 *)srcBitmap->bufferPtr();
for (int yCounter = count; --yCounter >= 0;) {
if (!_uses16BitColor) {
dst8 = (WizRawPixel8 *)dstBitmap->bufferPtr();
dst8 += drawSpans->dstOffset;
} else {
dst16 = (WizRawPixel16 *)dstBitmap->bufferPtr();
dst16 += drawSpans->dstOffset;
}
xOffset = drawSpans->xSrcOffset;
yOffset = drawSpans->ySrcOffset;
xStep = drawSpans->xSrcStep;
yStep = drawSpans->ySrcStep;
for (int xCounter = drawSpans->dstWidth; --xCounter >= 0;) {
if (!_uses16BitColor) {
*dst8++ = *(src8 + (sw * WARP_FROM_FRAC(yOffset)) + WARP_FROM_FRAC(xOffset));
} else {
*dst16++ = *(src16 + (sw * WARP_FROM_FRAC(yOffset)) + WARP_FROM_FRAC(xOffset));
}
xOffset += xStep;
yOffset += yStep;
}
drawSpans++;
}
}
void Wiz::warpProcessDrawSpansTransparent(WizSimpleBitmap *dstBitmap, const WizSimpleBitmap *srcBitmap, const WarpWizOneDrawSpan *drawSpans, int count, WizRawPixel transparentColor) {
int xStep, yStep, sw, xOffset, yOffset;
const WizRawPixel8 *src8 = (WizRawPixel8 *)srcBitmap->bufferPtr();
const WizRawPixel16 *src16 = (WizRawPixel16 *)srcBitmap->bufferPtr();
WizRawPixel8 *dst8 = (WizRawPixel8 *)dstBitmap->bufferPtr();
WizRawPixel16 *dst16 = (WizRawPixel16 *)dstBitmap->bufferPtr();
WizRawPixel srcColor;
sw = srcBitmap->bitmapWidth;
for (int yCounter = count; --yCounter >= 0;) {
if (!_uses16BitColor) {
dst8 = (WizRawPixel8 *)dstBitmap->bufferPtr();
dst8 += drawSpans->dstOffset;
} else {
dst16 = (WizRawPixel16 *)dstBitmap->bufferPtr();
dst16 += drawSpans->dstOffset;
}
xOffset = drawSpans->xSrcOffset;
yOffset = drawSpans->ySrcOffset;
xStep = drawSpans->xSrcStep;
yStep = drawSpans->ySrcStep;
for (int xCounter = drawSpans->dstWidth; --xCounter >= 0;) {
if (!_uses16BitColor) {
srcColor = *(src8 + (sw * WARP_FROM_FRAC(yOffset)) + WARP_FROM_FRAC(xOffset));
if (srcColor != transparentColor) {
*dst8++ = (WizRawPixel8)srcColor;
} else {
dst8++;
}
} else {
srcColor = *(src16 + (sw * WARP_FROM_FRAC(yOffset)) + WARP_FROM_FRAC(xOffset));
if (srcColor != transparentColor) {
*dst16++ = (WizRawPixel16)srcColor;
} else {
dst16++;
}
}
xOffset += xStep;
yOffset += yStep;
}
drawSpans++;
}
}
void Wiz::warpProcessDrawSpansTransparentFiltered(WizSimpleBitmap *dstBitmap, const WizSimpleBitmap *srcBitmap, const WarpWizOneDrawSpan *drawSpans, int count, WizRawPixel transparentColor, const byte *pXmapColorTable, bool bIsHintColor, WizRawPixel hintColor) {
int srcWidth = srcBitmap->bitmapWidth;
const WizRawPixel8 *src8 = (WizRawPixel8 *)srcBitmap->bufferPtr();
const WizRawPixel16 *src16 = (WizRawPixel16 *)srcBitmap->bufferPtr();
bool bSkipFilter = false;
int xStep, yStep, xOffset, yOffset;
WizRawPixel srcColor, srcColorN, srcColorS, srcColorE, srcColorW;
int iCurrentX, iCurrentY, iXScan, iYScan;
WizRawPixel8 *dst8 = (WizRawPixel8 *)dstBitmap->bufferPtr();
WizRawPixel16 *dst16 = (WizRawPixel16 *)dstBitmap->bufferPtr();
// Set up a rect for clipping if needed
Common::Rect aSrcRect; // Source rectangle for clipping...
Common::Rect aScanRect; // Dest rectangle for clipping...
aSrcRect.left = 0;
aSrcRect.top = 0;
aSrcRect.right = srcWidth;
aSrcRect.bottom = srcBitmap->bitmapHeight;
iYScan = aSrcRect.bottom / count;
for (int yCounter = count; --yCounter >= 0;) {
if (!_uses16BitColor) {
dst8 = (WizRawPixel8 *)dstBitmap->bufferPtr();
dst8 += drawSpans->dstOffset;
} else {
dst16 = (WizRawPixel16 *)dstBitmap->bufferPtr();
dst16 += drawSpans->dstOffset;
}
xOffset = drawSpans->xSrcOffset;
yOffset = drawSpans->ySrcOffset;
xStep = drawSpans->xSrcStep;
yStep = drawSpans->ySrcStep;
iXScan = WARP_FROM_FRAC(xStep); // The width of the search should be the x step size...
for (int xCounter = drawSpans->dstWidth; --xCounter >= 0;) {
iCurrentX = WARP_FROM_FRAC(xOffset);
iCurrentY = WARP_FROM_FRAC(yOffset);
// Get the current color and the surrounding colors...
if (!_uses16BitColor) {
srcColor = *(src8 + (srcWidth * iCurrentY) + iCurrentX);
} else {
srcColor = *(src16 + (srcWidth * iCurrentY) + iCurrentX);
}
bSkipFilter = false;
if (bIsHintColor) {
// Check if we need to clip our scan rectangle...
aScanRect.left = iCurrentX - iXScan;
aScanRect.top = iCurrentY - iYScan;
aScanRect.right = iCurrentX + iXScan;
aScanRect.bottom = iCurrentY + iYScan;
findRectOverlap(&aScanRect, &aSrcRect);
// Scan through rect looking for hint color...
for (int yScan = aScanRect.top; yScan < aScanRect.bottom; ++yScan) {
for (int xScan = aScanRect.left; xScan < aScanRect.right; ++xScan) {
if (!_uses16BitColor) {
if ((*(src8 + (yScan * srcWidth) + xScan)) == hintColor) {
srcColor = hintColor;
bSkipFilter = true;
break;
}
} else {
if ((*(src16 + (yScan * srcWidth) + xScan)) == hintColor) {
srcColor = hintColor;
bSkipFilter = true;
break;
}
}
}
if (bSkipFilter) {
break;
}
}
}
if ((srcColor != transparentColor) && !bSkipFilter) {
// Check if top...
if (iCurrentY != 0) {
if (!_uses16BitColor) {
srcColorN = *(src8 + (srcWidth * (iCurrentY - 1)) + iCurrentX);
} else {
srcColorN = *(src16 + (srcWidth * (iCurrentY - 1)) + iCurrentX);
}
} else {
srcColorN = transparentColor;
}
// Check if bottom...
if (iCurrentY != aSrcRect.bottom) {
if (!_uses16BitColor) {
srcColorS = *(src8 + (srcWidth * (iCurrentY + 1)) + iCurrentX);
} else {
srcColorS = *(src16 + (srcWidth * (iCurrentY + 1)) + iCurrentX);
}
} else {
srcColorS = transparentColor;
}
// Check for left edge...
if (iCurrentX != 0) {
if (!_uses16BitColor) {
srcColorW = *(src8 + (srcWidth * iCurrentY) + (iCurrentX - 1));
} else {
srcColorW = *(src16 + (srcWidth * iCurrentY) + (iCurrentX - 1));
}
} else {
srcColorW = transparentColor;
}
// Check for right edge...
if (iCurrentX != aSrcRect.right) {
if (!_uses16BitColor) {
srcColorE = *(src8 + (srcWidth * iCurrentY) + (iCurrentX + 1));
} else {
srcColorE = *(src16 + (srcWidth * iCurrentY) + (iCurrentX + 1));
}
} else {
srcColorE = transparentColor;
}
// Make transparent color black...
if (srcColorN == transparentColor) {
srcColorN = srcColor;
}
if (srcColorS == transparentColor) {
srcColorS = srcColor;
}
if (srcColorW == transparentColor) {
srcColorW = srcColor;
}
if (srcColorE == transparentColor) {
srcColorE = srcColor;
}
if (!_uses16BitColor) {
// In 8 bit mode go around the pixel adding in colors (1/8 of the surrounding colors)
// from the xmap color table; this ignores transparent pixels...
srcColor = *(pXmapColorTable + (srcColorN * 256) + srcColor);
srcColor = *(pXmapColorTable + (srcColorS * 256) + srcColor);
srcColor = *(pXmapColorTable + (srcColorE * 256) + srcColor);
srcColor = *(pXmapColorTable + (srcColorW * 256) + srcColor);
} else {
int rs = 0, gs = 0, bs = 0;
float rd = 0, gd = 0, bd = 0;
// Get 1/4 of each surrounding pixel and add into source pixel...
rawPixelExtractComponents(srcColorN, rs, gs, bs);
rd += rs;
gd += gs;
bd += bs;
rawPixelExtractComponents(srcColorS, rs, gs, bs);
rd += rs;
gd += gs;
bd += bs;
rawPixelExtractComponents(srcColorW, rs, gs, bs);
rd += rs;
gd += gs;
bd += bs;
rawPixelExtractComponents(srcColorE, rs, gs, bs);
rd += rs;
gd += gs;
bd += bs;
// Average pixels...
rd /= 4.0f;
gd /= 4.0f;
bd /= 4.0f;
// Get source pixel colors...
rawPixelExtractComponents(srcColor, rs, gs, bs);
rd += rs;
gd += gs;
bd += bs;
// Now average the two...
rd /= 2.0f;
gd /= 2.0f;
bd /= 2.0f;
// Pack the pixel back up...
rawPixelPackComponents(srcColor, (int)rd, (int)gd, (int)bd);
}
}
if (srcColor != transparentColor) {
if (!_uses16BitColor) {
*dst8++ = srcColor;
} else {
*dst16++ = srcColor;
}
} else {
if (!_uses16BitColor) {
dst8++;
} else {
dst16++;
}
}
xOffset += xStep;
yOffset += yStep;
}
drawSpans++;
}
}
void Wiz::warpProcessDrawSpansMixColors(WizSimpleBitmap *dstBitmap, const WizSimpleBitmap *srcBitmap, const WarpWizOneDrawSpan *drawSpans, int count, WizRawPixel transparentColor, const byte *tablePtr) {
int xStep, yStep, sw, xOffset, yOffset;
WizRawPixel srcColor;
const WizRawPixel8 *src8 = (WizRawPixel8 *)srcBitmap->bufferPtr();
const WizRawPixel16 *src16 = (WizRawPixel16 *)srcBitmap->bufferPtr();
WizRawPixel8 *dst8 = (WizRawPixel8 *)dstBitmap->bufferPtr();
WizRawPixel16 *dst16 = (WizRawPixel16 *)dstBitmap->bufferPtr();
sw = srcBitmap->bitmapWidth;
for (int yCounter = count; --yCounter >= 0;) {
if (!_uses16BitColor) {
dst8 = (WizRawPixel8 *)dstBitmap->bufferPtr();
dst8 += drawSpans->dstOffset;
} else {
dst16 = (WizRawPixel16 *)dstBitmap->bufferPtr();
dst16 += drawSpans->dstOffset;
}
xOffset = drawSpans->xSrcOffset;
yOffset = drawSpans->ySrcOffset;
xStep = drawSpans->xSrcStep;
yStep = drawSpans->ySrcStep;
for (int xCounter = drawSpans->dstWidth; --xCounter >= 0;) {
if (!_uses16BitColor) {
srcColor = (*(src8 + (sw * WARP_FROM_FRAC(yOffset)) + WARP_FROM_FRAC(xOffset)));
if (srcColor != transparentColor) {
*dst8 = *(tablePtr + (srcColor * 256) + (*dst8));
dst8++;
} else {
dst8++;
}
} else {
srcColor = *(src16 + (sw * WARP_FROM_FRAC(yOffset)) + WARP_FROM_FRAC(xOffset));
*dst16 = WIZRAWPIXEL_50_50_MIX(WIZRAWPIXEL_50_50_PREMIX_COLOR(srcColor), WIZRAWPIXEL_50_50_PREMIX_COLOR(*dst16));
dst16++;
}
xOffset += xStep;
yOffset += yStep;
}
drawSpans++;
}
}
void Wiz::warpFillSpanWithLine(WarpWizOneSpanTable *st, const WarpWizPoint *dstA, const WarpWizPoint *dstB, const WarpWizPoint *srcA, const WarpWizPoint *srcB) {
WarpWizPoint dstStep, srcStep, dstPt, srcPt, dpt, spt;
int h, lx1, ly1, lx2, ly2;
WarpWizOneSpan *spanPtr;
dstPt.x = WARP_TO_FRAC(dstA->x);
srcPt.x = WARP_TO_FRAC(srcA->x);
srcPt.y = WARP_TO_FRAC(srcA->y);
h = abs(dstB->y - dstA->y) + 1;
dstStep.x = WARP_TO_FRAC((dstB->x - dstA->x)) / h;
srcStep.x = WARP_TO_FRAC((srcB->x - srcA->x)) / h;
srcStep.y = WARP_TO_FRAC((srcB->y - srcA->y)) / h;
spanPtr = &st->spans[(dstA->y - st->dstMinPt.y)];
if (srcA->x <= srcB->x) {
lx1 = srcA->x;
lx2 = srcB->x;
} else {
lx1 = srcB->x;
lx2 = srcA->x;
}
if (srcA->y <= srcB->y) {
ly1 = srcA->y;
ly2 = srcB->y;
} else {
ly1 = srcB->y;
ly2 = srcA->y;
}
for (int i = h; --i >= 0;) {
dpt.x = WARP_FROM_FRAC(dstPt.x + (WARP_FRAC_VALUE / 2));
spt.x = MAX<int>(lx1, MIN<int>(lx2, WARP_FROM_FRAC(srcPt.x + (WARP_FRAC_VALUE / 2))));
spt.y = MAX<int>(ly1, MIN<int>(ly2, WARP_FROM_FRAC(srcPt.y + (WARP_FRAC_VALUE / 2))));
if (dpt.x < spanPtr->dstLeft) {
spanPtr->dstLeft = dpt.x;
spanPtr->srcLeft = spt;
}
if (dpt.x > spanPtr->dstRight) {
spanPtr->dstRight = dpt.x;
spanPtr->srcRight = spt;
}
dstPt.x += dstStep.x;
srcPt.x += srcStep.x;
srcPt.y += srcStep.y;
if (dstA->y < dstB->y) {
spanPtr++;
} else {
spanPtr--;
}
}
}
void Wiz::warpProcessDrawSpansSampled(WizSimpleBitmap *dstBitmap, const WizSimpleBitmap *srcBitmap, const WarpWizOneDrawSpan *drawSpans, int count) {
// Setup read pointer and clipping limits for the sampling rect...
const WizRawPixel8 *src8 = (WizRawPixel8 *)srcBitmap->bufferPtr();
const WizRawPixel16 *src16 = (WizRawPixel16 *)srcBitmap->bufferPtr();
WizRawPixel8 *dst8 = (WizRawPixel8 *)dstBitmap->bufferPtr();
WizRawPixel16 *dst16 = (WizRawPixel16 *)dstBitmap->bufferPtr();
int sw = srcBitmap->bitmapWidth;
int srcXLimit = (srcBitmap->bitmapWidth - 1);
int srcYLimit = (srcBitmap->bitmapHeight - 1);
// Process all of the spans in this span collection...
for (int yCounter = count; --yCounter >= 0;) {
if (!_uses16BitColor) {
dst8 = (WizRawPixel8 *)dstBitmap->bufferPtr();
dst8 += drawSpans->dstOffset;
} else {
dst16 = (WizRawPixel16 *)dstBitmap->bufferPtr();
dst16 += drawSpans->dstOffset;
}
int xOffset = drawSpans->xSrcOffset;
int yOffset = drawSpans->ySrcOffset;
int xStep = drawSpans->xSrcStep;
int yStep = drawSpans->ySrcStep;
// Figure out the sample rect for this "slope"...
int sampleCx = (WARP_FROM_FRAC(xStep));
int sampleCy = (WARP_FROM_FRAC(yStep));
if (sampleCx < 0) {
sampleCx = -sampleCx;
}
if (sampleCy < 0) {
sampleCy = -sampleCy;
}
// Make the sampling area square using the largest delta...
if (sampleCx > sampleCy) {
sampleCy = sampleCx;
} else {
sampleCx = sampleCy;
}
int sampleXOffset = sampleCx;
int sampleYOffset = sampleCy;
// Process all pixels covered by this "span"...
for (int xCounter = drawSpans->dstWidth; --xCounter >= 0;) {
if (!_uses16BitColor) {
*dst8++ = (*(src8 + (sw * WARP_FROM_FRAC(yOffset)) + WARP_FROM_FRAC(xOffset)));
} else {
// Do a really lame sampling of the potential source pixels...
int sx = WARP_FROM_FRAC(xOffset);
int sy = WARP_FROM_FRAC(yOffset);
int sx1 = sx;
int sy1 = sy;
int sx2 = sx + sampleXOffset;
int sy2 = sy + sampleYOffset;
// Clip the source sample coords to the bitmap limits...
sx1 = MAX<int>(0, MIN<int>(srcXLimit, sx1));
sy1 = MAX<int>(0, MIN<int>(srcYLimit, sy1));
sx2 = MAX<int>(0, MIN<int>(srcXLimit, sx2));
sy2 = MAX<int>(0, MIN<int>(srcYLimit, sy2));
// Now that the clipping is done figure out the sampling area...
int sxc = ((sx2 - sx1) + 1);
int syc = ((sy2 - sy1) + 1);
int total = (sxc * syc);
// Sample pixels from the source potential sampling area...
if (total > 1) {
int totalR, totalG, totalB;
const WizRawPixel *samplePtr = (const WizRawPixel *)(src16 + ((sw * sy1) + sx1));
rawPixelExtractComponents(*samplePtr, totalR, totalG, totalB);
int sampleStep = sw - sxc;
++total;
for (sy = 0; sy < syc; sy++) {
for (sx = 0; sx < sxc; sx++) {
int r, g, b;
WizRawPixel srcColor = *samplePtr++;
rawPixelExtractComponents(srcColor, r, g, b);
totalR += r;
totalG += g;
totalB += b;
}
samplePtr += sampleStep;
}
rawPixelPackComponents(*dst16, totalR / total, totalG / total, totalB / total);
} else {
*dst16 = (*(src16 + (sw * sy1) + sx1));
}
}
xOffset += xStep;
yOffset += yStep;
}
drawSpans++;
}
}
void Wiz::warpProcessDrawSpansTransparentSampled(WizSimpleBitmap *dstBitmap, const WizSimpleBitmap *srcBitmap, const WarpWizOneDrawSpan *drawSpans, int count, WizRawPixel transparentColor) {
// Setup read pointer and clipping limits for the sampling rect...
const WizRawPixel8 *src8 = (WizRawPixel8 *)srcBitmap->bufferPtr();
const WizRawPixel16 *src16 = (WizRawPixel16 *)srcBitmap->bufferPtr();
WizRawPixel8 *dst8 = (WizRawPixel8 *)dstBitmap->bufferPtr();
WizRawPixel16 *dst16 = (WizRawPixel16 *)dstBitmap->bufferPtr();
int sw = srcBitmap->bitmapWidth;
int srcXLimit = (srcBitmap->bitmapWidth - 1);
int srcYLimit = (srcBitmap->bitmapHeight - 1);
// Process all of the spans in this span collection...
for (int yCounter = count; --yCounter >= 0;) {
if (!_uses16BitColor) {
dst8 = (WizRawPixel8 *)dstBitmap->bufferPtr();
dst8 += drawSpans->dstOffset;
} else {
dst16 = (WizRawPixel16 *)dstBitmap->bufferPtr();
dst16 += drawSpans->dstOffset;
}
int xOffset = drawSpans->xSrcOffset;
int yOffset = drawSpans->ySrcOffset;
int xStep = drawSpans->xSrcStep;
int yStep = drawSpans->ySrcStep;
// Figure out the sample rect for this "slope"...
int sampleCx = (WARP_FROM_FRAC(xStep));
int sampleCy = (WARP_FROM_FRAC(yStep));
if (sampleCx < 0) {
sampleCx = -sampleCx;
}
if (sampleCy < 0) {
sampleCy = -sampleCy;
}
// Make the sampling area square using the largest delta...
if (sampleCx > sampleCy) {
sampleCy = sampleCx;
} else {
sampleCx = sampleCy;
}
int sampleXOffset = sampleCx;
int sampleYOffset = sampleCy;
// Process all pixels covered by this "span"...
for (int xCounter = drawSpans->dstWidth; --xCounter >= 0;) {
if (!_uses16BitColor) {
WizRawPixel srcColor = (*(src8 + (sw * WARP_FROM_FRAC(yOffset)) + WARP_FROM_FRAC(xOffset)));
if (srcColor != transparentColor) {
*dst8++ = srcColor;
} else {
dst8++;
}
} else {
// Do a really lame sampling of the potential source pixels...
int sx = WARP_FROM_FRAC(xOffset);
int sy = WARP_FROM_FRAC(yOffset);
int sx1 = sx;
int sy1 = sy;
int sx2 = sx + sampleXOffset;
int sy2 = sy + sampleYOffset;
// Clip the source sample coords to the bitmap limits...
sx1 = MAX<int>(0, MIN<int>(srcXLimit, sx1));
sy1 = MAX<int>(0, MIN<int>(srcYLimit, sy1));
sx2 = MAX<int>(0, MIN<int>(srcXLimit, sx2));
sy2 = MAX<int>(0, MIN<int>(srcYLimit, sy2));
// Now that the clipping is done figure out the sampling area...
int sxc = ((sx2 - sx1) + 1);
int syc = ((sy2 - sy1) + 1);
int total = (sxc * syc);
// Sample pixels from the source potential sampling area...
if (total > 1) {
int totalR, totalG, totalB;
const WizRawPixel *samplePtr = (const WizRawPixel *)(src16 + ((sw * sy1) + sx1));
WizRawPixel firstColor = (*(src16 + (sw * sy1) + sx1));
if (firstColor != transparentColor) {
rawPixelExtractComponents(*samplePtr, totalR, totalG, totalB);
++total;
} else {
totalR = 0;
totalG = 0;
totalB = 0;
}
int sampleStep = sw - sxc;
for (sy = 0; sy < syc; sy++) {
for (sx = 0; sx < sxc; sx++) {
WizRawPixel srcColor = *samplePtr++;
if (srcColor != transparentColor) {
int r, g, b;
rawPixelExtractComponents(srcColor, r, g, b);
totalR += r;
totalG += g;
totalB += b;
} else {
--total;
}
}
samplePtr += sampleStep;
}
if (total) {
WizRawPixel srcColor;
rawPixelPackComponents(srcColor, totalR / total, totalG / total, totalB / total);
if (transparentColor != srcColor) {
*dst16 = srcColor;
} else {
*dst16 = 4;
}
}
} else {
WizRawPixel srcColor = (*(src16 + (sw * sy1) + sx1));
if (srcColor != transparentColor) {
*dst16 = srcColor;
}
}
dst16++;
}
xOffset += xStep;
yOffset += yStep;
}
drawSpans++;
}
}
bool Wiz::warpNPt2NPtWarpCORE(WizSimpleBitmap *dstBitmap, const WarpWizPoint *dstpoints, const WizSimpleBitmap *srcBitmap, const WarpWizPoint *srcpoints, int npoints, int transparentColor, const Common::Rect *optionalClipRect, int32 wizFlags) {
WarpWizOneSpanTable *st;
if ((srcBitmap->bitmapWidth >= WARP_TEXTURE_LIMIT) || (srcBitmap->bitmapHeight >= WARP_TEXTURE_LIMIT)) {
error("Wiz::warpNPt2NPtWarpCORE(): Source bitmap (%d,%d) too big limit (%d,%d)",
srcBitmap->bitmapWidth, srcBitmap->bitmapHeight,
WARP_TEXTURE_LIMIT, WARP_TEXTURE_LIMIT);
}
st = warpBuildSpanTable(dstBitmap, srcBitmap, dstpoints, srcpoints, npoints, optionalClipRect);
if (st) {
if (st->drawSpanCount) {
if (transparentColor != -1) {
if (wizFlags & kWRFAreaSampleDuringWarp) {
warpProcessDrawSpansTransparentSampled(
dstBitmap, srcBitmap, st->drawSpans, st->drawSpanCount,
(WizRawPixel)transparentColor);
} else {
warpProcessDrawSpansTransparent(
dstBitmap, srcBitmap, st->drawSpans, st->drawSpanCount,
(WizRawPixel)transparentColor);
}
} else {
if (wizFlags & kWRFAreaSampleDuringWarp) {
warpProcessDrawSpansSampled(
dstBitmap, srcBitmap, st->drawSpans, st->drawSpanCount);
} else {
warpProcessDrawSpansA(
dstBitmap, srcBitmap, st->drawSpans, st->drawSpanCount);
}
}
}
warpDestroySpanTable(st);
return true;
}
warning("Wiz::warpNPt2NPtWarpCORE(): Unable to warp bitmap");
return false;
}
bool Wiz::warpNPt2NPtNonClippedWarp(WizSimpleBitmap *dstBitmap, const WarpWizPoint *dstpoints, const WizSimpleBitmap *srcBitmap, const WarpWizPoint *srcpoints, int npoints, int transparentColor) {
if (_vm->_game.heversion > 99) {
return warpNPt2NPtWarpCORE(
dstBitmap, dstpoints, srcBitmap, srcpoints,
npoints, transparentColor, nullptr, 0);
} else {
WarpWizOneSpanTable *st;
if ((srcBitmap->bitmapWidth >= WARP_TEXTURE_LIMIT) || (srcBitmap->bitmapHeight >= WARP_TEXTURE_LIMIT)) {
error("Wiz::warpNPt2NPtNonClippedWarp(): Source bitmap (%d,%d) too big limit (%d,%d)",
srcBitmap->bitmapWidth, srcBitmap->bitmapHeight,
WARP_TEXTURE_LIMIT, WARP_TEXTURE_LIMIT);
}
st = warpBuildSpanTable(dstBitmap, srcBitmap, dstpoints, srcpoints, npoints, nullptr);
if (st) {
if (st->drawSpanCount) {
if (transparentColor != -1) {
warpProcessDrawSpansTransparent(
dstBitmap, srcBitmap, st->drawSpans, st->drawSpanCount,
(WizRawPixel)transparentColor);
} else {
warpProcessDrawSpansA(dstBitmap, srcBitmap, st->drawSpans, st->drawSpanCount);
}
}
warpDestroySpanTable(st);
return true;
} else {
warning("Wiz::warpNPt2NPtNonClippedWarp(): Unable to warp bitmap");
return false;
}
}
}
bool Wiz::warpNPt2NPtClippedWarp(WizSimpleBitmap *dstBitmap, const WarpWizPoint *dstpoints, const WizSimpleBitmap *srcBitmap, const WarpWizPoint *srcpoints, int npoints, int transparentColor, const Common::Rect *optionalClipRect) {
if (_vm->_game.heversion > 99) {
return warpNPt2NPtWarpCORE(
dstBitmap, dstpoints, srcBitmap, srcpoints,
npoints, transparentColor, nullptr, 0);
} else {
WarpWizOneSpanTable *st;
if ((srcBitmap->bitmapWidth >= WARP_TEXTURE_LIMIT) || (srcBitmap->bitmapHeight >= WARP_TEXTURE_LIMIT)) {
error("Wiz::warpNPt2NPtClippedWarp(): Source bitmap (%d,%d) too big limit (%d,%d)",
srcBitmap->bitmapWidth, srcBitmap->bitmapHeight,
WARP_TEXTURE_LIMIT, WARP_TEXTURE_LIMIT);
}
st = warpBuildSpanTable(dstBitmap, srcBitmap, dstpoints, srcpoints, npoints, optionalClipRect);
if (st) {
if (st->drawSpanCount) {
if (transparentColor != -1) {
warpProcessDrawSpansTransparent(
dstBitmap, srcBitmap, st->drawSpans, st->drawSpanCount,
(WizRawPixel)transparentColor);
} else {
warpProcessDrawSpansA(dstBitmap, srcBitmap, st->drawSpans, st->drawSpanCount);
}
}
warpDestroySpanTable(st);
return true;
} else {
warning("Wiz::warpNPt2NPtClippedWarp(): Unable to warp bitmap");
return false;
}
}
}
bool Wiz::warpNPt2NPtClippedWarpMixColors(WizSimpleBitmap *dstBitmap, const WarpWizPoint *dstpoints, const WizSimpleBitmap *srcBitmap, const WarpWizPoint *srcpoints, int npoints, int transparentColor, const Common::Rect *optionalClipRect, const byte *colorMixTable) {
WarpWizOneSpanTable *st;
if ((srcBitmap->bitmapWidth >= WARP_TEXTURE_LIMIT) || (srcBitmap->bitmapHeight >= WARP_TEXTURE_LIMIT)) {
error("Wiz::warpNPt2NPtClippedWarpMixColors(): Source bitmap (%d,%d) too big limit (%d,%d)",
srcBitmap->bitmapWidth, srcBitmap->bitmapHeight,
WARP_TEXTURE_LIMIT, WARP_TEXTURE_LIMIT);
}
st = warpBuildSpanTable(
dstBitmap, srcBitmap, dstpoints, srcpoints, npoints, optionalClipRect);
if (st) {
if (st->drawSpanCount) {
warpProcessDrawSpansMixColors(
dstBitmap, srcBitmap, st->drawSpans, st->drawSpanCount,
transparentColor, colorMixTable);
}
warpDestroySpanTable(st);
return true;
} else {
warning("Wiz::warpNPt2NPtClippedWarpMixColors(): Unable to warp bitmap");
return false;
}
}
bool Wiz::warpNPt2NPtNonClippedWarpFiltered(WizSimpleBitmap *dstBitmap, const WarpWizPoint *dstpoints, const WizSimpleBitmap *srcBitmap, const WarpWizPoint *srcpoints, int npoints, int transparentColor, const byte *pXmapColorTable, bool bIsHintColor, WizRawPixel hintColor) {
WarpWizOneSpanTable *st;
if ((srcBitmap->bitmapWidth >= WARP_TEXTURE_LIMIT) || (srcBitmap->bitmapHeight >= WARP_TEXTURE_LIMIT)) {
error("Wiz::warpNPt2NPtNonClippedWarpFiltered(): Source bitmap (%d,%d) too big limit (%d,%d)",
srcBitmap->bitmapWidth, srcBitmap->bitmapHeight,
WARP_TEXTURE_LIMIT, WARP_TEXTURE_LIMIT);
}
st = warpBuildSpanTable(dstBitmap, srcBitmap, dstpoints, srcpoints, npoints, 0);
if (st) {
if (st->drawSpanCount) {
warpProcessDrawSpansTransparentFiltered(dstBitmap, srcBitmap, st->drawSpans,
st->drawSpanCount,(WizRawPixel)transparentColor, pXmapColorTable, bIsHintColor, hintColor);
}
warpDestroySpanTable(st);
return true;
} else {
warning("Wiz::warpNPt2NPtNonClippedWarpFiltered(): Unable to warp bitmap");
return false;
}
}
} // End of namespace Scumm
#endif // ENABLE_HE