mirror of
https://github.com/libretro/scummvm.git
synced 2025-01-29 23:01:58 +00:00
219 lines
5.6 KiB
C++
219 lines
5.6 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 2
|
|
* 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, write to the Free Software
|
|
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
|
*
|
|
*/
|
|
|
|
#include "common/algorithm.h"
|
|
#include "common/util.h"
|
|
#include "xeen/xsurface.h"
|
|
#include "xeen/resources.h"
|
|
#include "xeen/screen.h"
|
|
|
|
namespace Xeen {
|
|
|
|
XSurface::XSurface() : Graphics::Surface(), _freeFlag(false) {
|
|
}
|
|
|
|
XSurface::XSurface(int w, int h) : Graphics::Surface(), _freeFlag(false) {
|
|
create(w, h);
|
|
}
|
|
|
|
XSurface::~XSurface() {
|
|
if (_freeFlag)
|
|
free();
|
|
}
|
|
|
|
void XSurface::create(uint16 w, uint16 h) {
|
|
Graphics::Surface::create(w, h, Graphics::PixelFormat::createFormatCLUT8());
|
|
_freeFlag = true;
|
|
}
|
|
|
|
void XSurface::create(XSurface *s, const Common::Rect &bounds) {
|
|
pixels = (byte *)s->getBasePtr(bounds.left, bounds.top);
|
|
format = Graphics::PixelFormat::createFormatCLUT8();
|
|
pitch = s->pitch;
|
|
w = bounds.width();
|
|
h = bounds.height();
|
|
|
|
_freeFlag = false;
|
|
}
|
|
|
|
|
|
void XSurface::transBlitTo(XSurface &dest) const {
|
|
transBlitTo(dest, Common::Point());
|
|
}
|
|
|
|
void XSurface::blitTo(XSurface &dest) const {
|
|
blitTo(dest, Common::Point());
|
|
}
|
|
|
|
void XSurface::transBlitTo(XSurface &dest, const Common::Point &destPos) const {
|
|
if (dest.getPixels() == nullptr)
|
|
dest.create(w, h);
|
|
|
|
for (int yp = 0; yp < h; ++yp) {
|
|
const byte *srcP = (const byte *)getBasePtr(0, yp);
|
|
byte *destP = (byte *)dest.getBasePtr(destPos.x, destPos.y + yp);
|
|
|
|
for (int xp = 0; xp < w; ++xp, ++srcP, ++destP) {
|
|
if (*srcP != 0)
|
|
*destP = *srcP;
|
|
}
|
|
}
|
|
|
|
dest.addDirtyRect(Common::Rect(destPos.x, destPos.y, destPos.x + w, destPos.y));
|
|
}
|
|
|
|
void XSurface::transBlitTo(XSurface &dest, const Common::Point &destPos,
|
|
int scale, int transparentColor) {
|
|
int destX = destPos.x, destY = destPos.y;
|
|
int frameWidth = this->w;
|
|
int frameHeight = this->h;
|
|
int direction = 1;
|
|
|
|
int highestDim = MAX(frameWidth, frameHeight);
|
|
bool lineDist[SCREEN_WIDTH];
|
|
int distXCount = 0, distYCount = 0;
|
|
|
|
if (scale != 0) {
|
|
int distCtr = 0;
|
|
int distIndex = 0;
|
|
do {
|
|
distCtr += scale;
|
|
if (distCtr < 100) {
|
|
lineDist[distIndex] = false;
|
|
}
|
|
else {
|
|
lineDist[distIndex] = true;
|
|
distCtr -= 100;
|
|
|
|
if (distIndex < frameWidth)
|
|
++distXCount;
|
|
|
|
if (distIndex < frameHeight)
|
|
++distYCount;
|
|
}
|
|
} while (++distIndex < highestDim);
|
|
|
|
destX += (this->w - distXCount) / 2;
|
|
destY += (this->h - distYCount) / 2;
|
|
}
|
|
|
|
// Start of draw logic for scaled sprites
|
|
const byte *srcPixelsP = (const byte *)getPixels();
|
|
|
|
int destRight = dest.w - 1;
|
|
int destBottom = dest.h - 1;
|
|
|
|
// Check x bounding area
|
|
int spriteLeft = 0;
|
|
int spriteWidth = distXCount;
|
|
int widthAmount = destX + distXCount - 1;
|
|
|
|
if (destX < 0) {
|
|
spriteWidth += destX;
|
|
spriteLeft -= destX;
|
|
}
|
|
widthAmount -= destRight;
|
|
if (widthAmount > 0)
|
|
spriteWidth -= widthAmount;
|
|
|
|
if (spriteWidth <= 0)
|
|
return;
|
|
|
|
// Check y bounding area
|
|
int spriteTop = 0;
|
|
int spriteHeight = distYCount;
|
|
int heightAmount = destY + distYCount - 1;
|
|
|
|
if (destY < 0) {
|
|
spriteHeight += destY;
|
|
spriteTop -= destY;
|
|
}
|
|
heightAmount -= destBottom;
|
|
if (heightAmount > 0)
|
|
spriteHeight -= heightAmount;
|
|
int spriteBottom = spriteTop + spriteHeight;
|
|
|
|
if (spriteHeight <= 0)
|
|
return;
|
|
|
|
byte *destPixelsP = (byte *)dest.getBasePtr(destX + spriteLeft, destY + spriteTop);
|
|
int destWidth = 0, destHeight = 0;
|
|
|
|
spriteLeft = spriteLeft * direction;
|
|
|
|
// Loop through the lines of the sprite
|
|
for (int yp = 0, sprY = -1; yp < frameHeight; ++yp, srcPixelsP += this->pitch) {
|
|
if (!lineDist[yp])
|
|
// Not a display line, so skip it
|
|
continue;
|
|
// Check whether the sprite line is in the display range
|
|
++sprY;
|
|
if ((sprY >= spriteBottom) || (sprY < spriteTop))
|
|
continue;
|
|
|
|
// Found a line to display. Loop through the pixels
|
|
const byte *srcP = srcPixelsP;
|
|
byte *destP = destPixelsP;
|
|
++destHeight;
|
|
|
|
for (int xp = 0, sprX = 0; xp < frameWidth; ++xp, ++srcP) {
|
|
if (xp < spriteLeft)
|
|
// Not yet reached start of display area
|
|
continue;
|
|
if (!lineDist[sprX++])
|
|
// Not a display pixel
|
|
continue;
|
|
|
|
if (*srcP != transparentColor)
|
|
*destP = *srcP;
|
|
|
|
destP += direction;
|
|
}
|
|
|
|
// Keep track of widest line drawn
|
|
destWidth = MAX(destP - destPixelsP, destWidth);
|
|
|
|
// Move to the next destination line
|
|
destPixelsP += dest.pitch;
|
|
}
|
|
|
|
// Add a dirty rect for the affected area
|
|
dest.addDirtyRect(Common::Rect(destX + spriteLeft, destY + spriteTop,
|
|
destX + spriteLeft + destWidth, destY + spriteTop + destHeight));
|
|
}
|
|
|
|
void XSurface::blitTo(XSurface &dest, const Common::Point &destPos) const {
|
|
if (dest.getPixels() == nullptr)
|
|
dest.create(w, h);
|
|
|
|
for (int yp = 0; yp < h; ++yp) {
|
|
const byte *srcP = (const byte *)getBasePtr(0, yp);
|
|
byte *destP = (byte *)dest.getBasePtr(destPos.x, destPos.y + yp);
|
|
|
|
Common::copy(srcP, srcP + w, destP);
|
|
}
|
|
|
|
dest.addDirtyRect(Common::Rect(destPos.x, destPos.y, destPos.x + w, destPos.y + h));
|
|
}
|
|
|
|
} // End of namespace Xeen
|