mirror of
https://github.com/scummvm/scummvm.git
synced 2026-06-20 05:45:29 +00:00
219 lines
6.7 KiB
C++
219 lines
6.7 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/>.
|
|
*
|
|
*/
|
|
|
|
#include "scumm/he/intern_he.h"
|
|
#include "engines/scumm/he/moonbase/moonbase.h"
|
|
|
|
namespace Scumm {
|
|
|
|
enum {
|
|
kBptHeaderSize = 8,
|
|
|
|
kReflectionClipped = 0,
|
|
kNotClipped = 1,
|
|
kSpecializedNotClipped = 2
|
|
};
|
|
|
|
static void blitDistortionCore(
|
|
Graphics::Surface *dstBitmap,
|
|
const int x, const int y,
|
|
const Graphics::Surface *distortionBitmap,
|
|
const Common::Rect *optionalclipRectPtr,
|
|
int transferOp,
|
|
const Graphics::Surface *srcBitmap,
|
|
Common::Rect *srcClipRect
|
|
) {
|
|
Common::Rect clipRect(dstBitmap->w, dstBitmap->h);
|
|
|
|
if (optionalclipRectPtr) {
|
|
if (!clipRect.intersects(*optionalclipRectPtr))
|
|
return;
|
|
|
|
clipRect.clip(*optionalclipRectPtr);
|
|
}
|
|
|
|
Common::Rect distortionRect(distortionBitmap->w, distortionBitmap->h);
|
|
Common::Rect dstRect(x, y, x + distortionRect.width(), y + distortionRect.height());
|
|
|
|
if (!dstRect.intersects(clipRect))
|
|
return;
|
|
|
|
dstRect.clip(clipRect);
|
|
|
|
distortionRect.moveTo(dstRect.left - x, dstRect.top - y);
|
|
|
|
const byte *distortionPtr = (const byte *)distortionBitmap->getBasePtr(distortionRect.left, distortionRect.top);
|
|
byte *dstPtr = (byte *)dstBitmap->getBasePtr(dstRect.left, dstRect.top);
|
|
int cw = dstRect.width();
|
|
int ch = dstRect.height();
|
|
int idx = dstRect.left;
|
|
int dy = dstRect.top;
|
|
|
|
int baseX, baseY;
|
|
const byte *srcData = (const byte *)srcBitmap->getBasePtr(0, 0);
|
|
int srcPitch = srcBitmap->pitch;
|
|
|
|
switch (transferOp) {
|
|
case kReflectionClipped:
|
|
case kNotClipped:
|
|
baseX = -(0x1f / 2); // Half range
|
|
baseY = -(0x1f / 2);
|
|
break;
|
|
|
|
case kSpecializedNotClipped:
|
|
default:
|
|
baseX = 0;
|
|
baseY = 0;
|
|
}
|
|
|
|
while (--ch >= 0) {
|
|
uint16 *d = (uint16 *)dstPtr;
|
|
const uint16 *is = (const uint16 *)distortionPtr;
|
|
int dx = idx;
|
|
|
|
for (int i = cw; --i >= 0;) {
|
|
uint16 p = READ_LE_UINT16(is);
|
|
int sx = baseX + dx + ((p >> 5) & 0x1f); // G color
|
|
int sy = baseY + dy + (p & 0x1f); // B color;
|
|
|
|
if (transferOp == kReflectionClipped) {
|
|
if (sx < srcClipRect->left)
|
|
sx -= (srcClipRect->left - sx);
|
|
|
|
if (sx > srcClipRect->right)
|
|
sx -= (sx - srcClipRect->right);
|
|
|
|
sx = MAX<int>(srcClipRect->left, MIN<int>(sx, srcClipRect->right));
|
|
|
|
if (sy < srcClipRect->top)
|
|
sy -= (srcClipRect->top - sy);
|
|
|
|
if (sy > srcClipRect->bottom)
|
|
sy -= (sy - srcClipRect->bottom);
|
|
|
|
sy = MAX<int>(srcClipRect->top, MIN<int>(sy, srcClipRect->bottom));
|
|
}
|
|
|
|
*d = *((const uint16 *)(srcData + sy * srcPitch + sx * 2));
|
|
|
|
++d;
|
|
++is;
|
|
++dx;
|
|
}
|
|
|
|
dstPtr += dstBitmap->pitch;
|
|
distortionPtr += distortionBitmap->pitch;
|
|
|
|
++dy;
|
|
}
|
|
}
|
|
|
|
void Moonbase::blitDistortion(byte *bufferData, const int bufferWidth, const int bufferHeight, const int bufferPitch,
|
|
const Common::Rect *optionalClippingRect, byte *dataStream, const int x, const int y, byte *altSourceBuffer) {
|
|
byte *sourcePixels = (altSourceBuffer) ? altSourceBuffer : bufferData;
|
|
Common::Rect dstLimitsRect(bufferWidth, bufferHeight);
|
|
Common::Rect clippedDstRect = dstLimitsRect;
|
|
|
|
if (optionalClippingRect) {
|
|
if (!dstLimitsRect.intersects(*optionalClippingRect))
|
|
return;
|
|
dstLimitsRect.clip(*optionalClippingRect);
|
|
} else {
|
|
clippedDstRect = dstLimitsRect;
|
|
}
|
|
|
|
int w = READ_LE_UINT16(dataStream + kBptHeaderSize + 0);
|
|
int h = READ_LE_UINT16(dataStream + kBptHeaderSize + 2);
|
|
Common::Rect srcLimitsRect(w, h);
|
|
Common::Rect clippedSrcRect = srcLimitsRect;
|
|
Common::Rect dstOperation(x, y, x + clippedSrcRect.width(), y + clippedSrcRect.height());
|
|
|
|
if (!clippedDstRect.intersects(dstOperation))
|
|
return;
|
|
|
|
clippedDstRect.clip(dstOperation);
|
|
|
|
int subBlockCount = READ_LE_UINT16(dataStream + kBptHeaderSize + 4);
|
|
byte *subBlockStream = dataStream + kBptHeaderSize + READ_LE_UINT32(dataStream + 4);
|
|
int cx1 = clippedDstRect.left;
|
|
int cy1 = clippedDstRect.top;
|
|
int cx2 = clippedDstRect.right - 1;
|
|
int cy2 = clippedDstRect.bottom - 1;
|
|
|
|
for (int i = 0; i < subBlockCount; i++) {
|
|
byte *blockData = subBlockStream;
|
|
uint32 blockSize = READ_LE_UINT32(blockData); blockData += 4;
|
|
subBlockStream += blockSize;
|
|
int xOffset = READ_LE_UINT16(blockData); blockData += 2;
|
|
int yOffset = READ_LE_UINT16(blockData); blockData += 2;
|
|
int width = READ_LE_UINT16(blockData); blockData += 2;
|
|
int height = READ_LE_UINT16(blockData); blockData += 2;
|
|
int l_reach = READ_LE_UINT16(blockData); blockData += 2;
|
|
int r_reach = READ_LE_UINT16(blockData); blockData += 2;
|
|
int t_reach = READ_LE_UINT16(blockData); blockData += 2;
|
|
int b_reach = READ_LE_UINT16(blockData); blockData += 2;
|
|
int distortionPitch = ((width * 2 + 7) / 8); // 2 for 555
|
|
|
|
if (width == 0 && height == 0)
|
|
continue;
|
|
|
|
Graphics::Surface dstBitmap;
|
|
dstBitmap.init(bufferWidth, bufferHeight, bufferPitch, bufferData, Graphics::PixelFormat(2, 5, 5, 5, 0, 10, 5, 0, 0));
|
|
|
|
Graphics::Surface srcBitmap;
|
|
srcBitmap.init(bufferWidth, bufferHeight, bufferPitch, sourcePixels, Graphics::PixelFormat(2, 5, 5, 5, 0, 10, 5, 0, 0));
|
|
|
|
Graphics::Surface distortionBitmap;
|
|
distortionBitmap.init(width, height, distortionPitch, blockData, Graphics::PixelFormat(2, 5, 5, 5, 0, 10, 5, 0, 0));
|
|
|
|
Common::Rect srcClipRect(cx1, cy1, cx2, cy2);
|
|
Common::Rect dstClipRect(cx1, cy1, cx2, cy2);
|
|
|
|
int src_x = (x + xOffset);
|
|
int src_y = (y + yOffset);
|
|
|
|
Common::Rect srcReach((src_x - l_reach), (src_y - t_reach), (src_x + r_reach), (src_y + b_reach));
|
|
Common::Rect srcLimits(srcBitmap.w, srcBitmap.h);
|
|
|
|
if (!srcLimits.intersects(srcClipRect))
|
|
return;
|
|
|
|
srcLimits.clip(srcClipRect);
|
|
|
|
if (!srcReach.intersects(srcLimits))
|
|
return;
|
|
|
|
srcReach.clip(srcLimits);
|
|
|
|
if (srcLimits.contains(srcReach)) {
|
|
if (srcBitmap.pitch == 1280) {
|
|
blitDistortionCore(&dstBitmap, src_x, src_y, &distortionBitmap, &dstClipRect, kSpecializedNotClipped, &srcBitmap, 0);
|
|
} else {
|
|
blitDistortionCore(&dstBitmap, src_x, src_y, &distortionBitmap, &dstClipRect, kNotClipped, &srcBitmap, 0);
|
|
}
|
|
} else {
|
|
blitDistortionCore(&dstBitmap, src_x, src_y, &distortionBitmap, &dstClipRect, kReflectionClipped, &srcBitmap, &srcLimits);
|
|
}
|
|
}
|
|
}
|
|
|
|
}
|