Initial commit
This commit is contained in:
229
engines/bagel/mfc/gfx/blitter.cpp
Normal file
229
engines/bagel/mfc/gfx/blitter.cpp
Normal file
@@ -0,0 +1,229 @@
|
||||
/* 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 "common/textconsole.h"
|
||||
#include "bagel/mfc/gfx/blitter.h"
|
||||
#include "bagel/mfc/afxwin.h"
|
||||
|
||||
namespace Bagel {
|
||||
namespace MFC {
|
||||
namespace Gfx {
|
||||
|
||||
static inline void copyPixel(const byte *srcP, byte *destP, int mode, const byte &WHITE,
|
||||
bool isDestMonochrome, uint bgColor, const uint32 *paletteMap) {
|
||||
byte src = *srcP;
|
||||
if (paletteMap)
|
||||
src = paletteMap[src];
|
||||
|
||||
switch (mode) {
|
||||
case SRCCOPY:
|
||||
*destP = src;
|
||||
break;
|
||||
case SRCAND:
|
||||
*destP &= src;
|
||||
break;
|
||||
case SRCINVERT:
|
||||
*destP ^= src;
|
||||
break;
|
||||
case SRCPAINT:
|
||||
*destP |= src;
|
||||
break;
|
||||
case NOTSRCCOPY:
|
||||
if (isDestMonochrome) {
|
||||
*destP = src == bgColor ? 0 : 0xff;
|
||||
return;
|
||||
}
|
||||
|
||||
*destP = ~src;
|
||||
break;
|
||||
case DSTINVERT:
|
||||
*destP = ~*destP;
|
||||
return;
|
||||
case BLACKNESS:
|
||||
*destP = 0;
|
||||
return;
|
||||
case WHITENESS:
|
||||
*destP = WHITE;
|
||||
return;
|
||||
default:
|
||||
error("Unsupported blit mode");
|
||||
break;
|
||||
}
|
||||
|
||||
if (isDestMonochrome)
|
||||
*destP = *destP == bgColor ? 0xff : 0;
|
||||
}
|
||||
|
||||
static void blitInner(Gfx::Surface *srcSurface,
|
||||
Gfx::Surface *destSurface,
|
||||
const Common::Rect &srcRect, const Common::Point &destPos,
|
||||
uint bgColor, int mode, const uint32 *paletteMap) {
|
||||
const bool isDestMonochrome = destSurface->format.bytesPerPixel == 1 &&
|
||||
destSurface->format.aLoss == 255;
|
||||
const byte WHITE = 255;
|
||||
Surface::YIterator ySrc(srcSurface);
|
||||
Surface::XIterator xSrc(&ySrc);
|
||||
Surface::YIterator yDest(destSurface);
|
||||
Surface::XIterator xDest(&yDest);
|
||||
byte dummy = 0;
|
||||
byte *srcP, *destP;
|
||||
|
||||
for (ySrc = srcRect.top, yDest = destPos.y; ySrc < srcRect.bottom; ++ySrc, ++yDest) {
|
||||
for (xSrc = srcRect.left, xDest = destPos.x; xSrc < srcRect.right; ++xSrc, ++xDest) {
|
||||
srcP = xSrc;
|
||||
destP = xDest;
|
||||
if (!srcP)
|
||||
srcP = &dummy;
|
||||
if (!destP)
|
||||
destP = &dummy;
|
||||
|
||||
copyPixel(srcP, destP, mode, WHITE, isDestMonochrome, bgColor, paletteMap);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void stretchBlitInner(Gfx::Surface *srcSurface,
|
||||
Gfx::Surface *destSurface,
|
||||
const Common::Rect &srcRect, const Common::Rect &dstRect,
|
||||
uint bgColor, int mode, const uint32 *paletteMap) {
|
||||
const bool isDestMonochrome = destSurface->format.bytesPerPixel == 1 &&
|
||||
destSurface->format.aLoss == 255;
|
||||
const byte WHITE = 255;
|
||||
const int srcWidth = srcRect.right - srcRect.left;
|
||||
const int srcHeight = srcRect.bottom - srcRect.top;
|
||||
const int dstWidth = dstRect.right - dstRect.left;
|
||||
const int dstHeight = dstRect.bottom - dstRect.top;
|
||||
Surface::YIterator ySrc(srcSurface);
|
||||
Surface::XIterator xSrc(&ySrc);
|
||||
Surface::YIterator yDest(destSurface);
|
||||
Surface::XIterator xDest(&yDest);
|
||||
|
||||
if (srcWidth <= 0 || srcHeight <= 0 || dstWidth <= 0 || dstHeight <= 0)
|
||||
return; // Invalid rectangles
|
||||
|
||||
for (int y = 0; y < dstHeight; ++y) {
|
||||
// Map destination y to source y using fixed-point arithmetic
|
||||
int srcY = srcRect.top + (y * srcHeight) / dstHeight;
|
||||
if (srcY >= srcSurface->h)
|
||||
continue;
|
||||
|
||||
int dstY = dstRect.top + y;
|
||||
if (dstY >= destSurface->h)
|
||||
continue;
|
||||
|
||||
for (int x = 0; x < dstWidth; ++x) {
|
||||
int srcX = srcRect.left + (x * srcWidth) / dstWidth;
|
||||
if (srcX >= srcSurface->w)
|
||||
continue;
|
||||
int dstX = dstRect.left + x;
|
||||
if (dstX >= destSurface->w)
|
||||
continue;
|
||||
|
||||
xSrc = srcX;
|
||||
ySrc = srcY;
|
||||
byte *srcP = xSrc;
|
||||
xDest = dstX;
|
||||
yDest = dstY;
|
||||
byte *destP = xDest;
|
||||
|
||||
copyPixel(srcP, destP, mode, WHITE, isDestMonochrome, bgColor, paletteMap);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void blit(Gfx::Surface *src, Gfx::Surface *dest,
|
||||
const Common::Rect &srcRect, const Common::Point &destPos,
|
||||
uint bgColor, int mode, const uint32 *paletteMap) {
|
||||
// For normal copying modes, the formats must match.
|
||||
// Other modes like DSTINVERT don't need a source,
|
||||
// so in that case the source can remain uninitialized
|
||||
assert(src->format.bytesPerPixel == dest->format.bytesPerPixel ||
|
||||
src->format.bytesPerPixel == 0);
|
||||
assert(dest->format.bytesPerPixel == dest->format.bytesPerPixel ||
|
||||
dest->format.bytesPerPixel == 0);
|
||||
|
||||
blitInner(src, dest, srcRect, destPos, bgColor, mode, paletteMap);
|
||||
|
||||
Common::Rect dirtyRect(destPos.x, destPos.y,
|
||||
destPos.x + srcRect.width(), destPos.y + srcRect.height());
|
||||
dest->addDirtyRect(dirtyRect);
|
||||
}
|
||||
|
||||
void stretchBlit(Gfx::Surface *src, Gfx::Surface *dest,
|
||||
const Common::Rect &srcRect, const Common::Rect &destRect,
|
||||
uint bgColor, int mode, const uint32 *paletteMap) {
|
||||
assert(src->format.bytesPerPixel == dest->format.bytesPerPixel ||
|
||||
src->format.bytesPerPixel == 0);
|
||||
assert(dest->format.bytesPerPixel == dest->format.bytesPerPixel ||
|
||||
dest->format.bytesPerPixel == 0);
|
||||
|
||||
stretchBlitInner(src, dest, srcRect, destRect, bgColor, mode, paletteMap);
|
||||
}
|
||||
|
||||
static inline void rasterPixel(byte *pixel, byte) {
|
||||
// Currently only R2_NOT
|
||||
*pixel = ~*pixel;
|
||||
}
|
||||
|
||||
void frameRect(Gfx::Surface *dest,
|
||||
const Common::Rect &r, byte color, int drawMode) {
|
||||
assert(dest->format.bytesPerPixel == 1);
|
||||
|
||||
if (drawMode == R2_COPYPEN) {
|
||||
dest->frameRect(r, color);
|
||||
return;
|
||||
} else if (drawMode == R2_NOP) {
|
||||
return;
|
||||
}
|
||||
|
||||
assert(drawMode == R2_NOT);
|
||||
|
||||
const int w = r.right - r.left;
|
||||
const int h = r.bottom - r.top - 2;
|
||||
byte *pixel;
|
||||
|
||||
// Top line
|
||||
pixel = (byte *)dest->getBasePtr(r.left, r.top);
|
||||
for (int x = 0; x < w; ++x, ++pixel)
|
||||
rasterPixel(pixel, color);
|
||||
|
||||
// Bottom line
|
||||
pixel = (byte *)dest->getBasePtr(r.left, r.bottom - 1);
|
||||
for (int x = 0; x < w; ++x, ++pixel)
|
||||
rasterPixel(pixel, color);
|
||||
|
||||
// Left edge
|
||||
pixel = (byte *)dest->getBasePtr(r.left, r.top + 1);
|
||||
for (int y = 0; y < h; ++y, pixel += dest->pitch)
|
||||
rasterPixel(pixel, color);
|
||||
|
||||
// Right edge
|
||||
pixel = (byte *)dest->getBasePtr(r.right - 1, r.top + 1);
|
||||
for (int y = 0; y < h; ++y, pixel += dest->pitch)
|
||||
rasterPixel(pixel, color);
|
||||
|
||||
// Mark the rectangle area as dirty
|
||||
dest->addDirtyRect(r);
|
||||
}
|
||||
|
||||
} // namespace Gfx
|
||||
} // namespace MFC
|
||||
} // namespace Bagel
|
||||
Reference in New Issue
Block a user