2007-05-30 21:56:52 +00:00
|
|
|
/* ScummVM - Graphic Adventure Engine
|
2004-04-12 21:40:49 +00:00
|
|
|
*
|
2007-05-30 21:56:52 +00:00
|
|
|
* 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.
|
2004-04-12 21:40:49 +00:00
|
|
|
*
|
|
|
|
* 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.
|
2014-02-18 01:34:24 +00:00
|
|
|
*
|
2004-04-12 21:40:49 +00:00
|
|
|
* This program is distributed in the hope that it will be useful,
|
|
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
2008-01-05 12:45:14 +00:00
|
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
2004-04-12 21:40:49 +00:00
|
|
|
* GNU General Public License for more details.
|
2014-02-18 01:34:24 +00:00
|
|
|
*
|
2004-04-12 21:40:49 +00:00
|
|
|
* You should have received a copy of the GNU General Public License
|
|
|
|
* along with this program; if not, write to the Free Software
|
2005-10-18 01:30:26 +00:00
|
|
|
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
2004-04-12 21:40:49 +00:00
|
|
|
*
|
|
|
|
*/
|
|
|
|
|
2004-05-01 16:15:55 +00:00
|
|
|
// Sprite management module
|
2007-07-31 18:08:40 +00:00
|
|
|
|
2004-08-02 16:20:35 +00:00
|
|
|
#include "saga/saga.h"
|
2004-04-12 21:40:49 +00:00
|
|
|
|
2004-08-02 16:20:35 +00:00
|
|
|
#include "saga/gfx.h"
|
2004-08-04 20:28:57 +00:00
|
|
|
#include "saga/scene.h"
|
2008-12-22 14:13:15 +00:00
|
|
|
#include "saga/resource.h"
|
2004-08-03 00:06:18 +00:00
|
|
|
#include "saga/font.h"
|
2004-04-12 21:40:49 +00:00
|
|
|
|
2004-08-02 16:20:35 +00:00
|
|
|
#include "saga/sprite.h"
|
2008-12-07 18:49:35 +00:00
|
|
|
#include "saga/render.h"
|
2004-04-12 21:40:49 +00:00
|
|
|
|
|
|
|
namespace Saga {
|
|
|
|
|
2008-05-26 11:10:46 +00:00
|
|
|
#define RID_IHNM_ARROW_SPRITES 13
|
|
|
|
#define RID_IHNM_SAVEREMINDER_SPRITES 14
|
|
|
|
#define RID_IHNMDEMO_ARROW_SPRITES 8
|
|
|
|
#define RID_IHNMDEMO_SAVEREMINDER_SPRITES 9
|
|
|
|
|
2005-07-19 19:05:52 +00:00
|
|
|
Sprite::Sprite(SagaEngine *vm) : _vm(vm) {
|
2005-07-05 16:58:36 +00:00
|
|
|
debug(8, "Initializing sprite subsystem...");
|
2004-04-12 21:40:49 +00:00
|
|
|
|
2004-05-01 16:15:55 +00:00
|
|
|
// Load sprite module resource context
|
2005-07-19 19:05:52 +00:00
|
|
|
_spriteContext = _vm->_resource->getContext(GAME_RESOURCEFILE);
|
2004-11-15 03:03:48 +00:00
|
|
|
if (_spriteContext == NULL) {
|
2005-07-19 19:05:52 +00:00
|
|
|
error("Sprite::Sprite resource context not found");
|
2004-04-12 21:40:49 +00:00
|
|
|
}
|
|
|
|
|
2008-12-21 15:59:05 +00:00
|
|
|
if (_vm->getGameId() == GID_ITE) {
|
2005-08-07 00:00:43 +00:00
|
|
|
loadList(_vm->getResourceDescription()->mainSpritesResourceId, _mainSprites);
|
2005-10-11 02:22:53 +00:00
|
|
|
_arrowSprites = _saveReminderSprites = _inventorySprites = _mainSprites;
|
2009-01-02 16:52:38 +00:00
|
|
|
#ifdef ENABLE_IHNM
|
2008-12-21 15:59:05 +00:00
|
|
|
} else if (_vm->getGameId() == GID_IHNM) {
|
2010-05-16 10:36:21 +00:00
|
|
|
if (_vm->isIHNMDemo()) {
|
2007-07-19 01:28:41 +00:00
|
|
|
loadList(RID_IHNMDEMO_ARROW_SPRITES, _arrowSprites);
|
|
|
|
loadList(RID_IHNMDEMO_SAVEREMINDER_SPRITES, _saveReminderSprites);
|
|
|
|
} else {
|
|
|
|
loadList(RID_IHNM_ARROW_SPRITES, _arrowSprites);
|
|
|
|
loadList(RID_IHNM_SAVEREMINDER_SPRITES, _saveReminderSprites);
|
|
|
|
}
|
2009-01-02 16:52:38 +00:00
|
|
|
#endif
|
2008-12-21 15:59:05 +00:00
|
|
|
} else {
|
|
|
|
error("Sprite: unknown game type");
|
2005-10-10 02:42:50 +00:00
|
|
|
}
|
2004-04-12 21:40:49 +00:00
|
|
|
}
|
|
|
|
|
2009-11-02 21:54:57 +00:00
|
|
|
Sprite::~Sprite() {
|
2005-07-05 16:58:36 +00:00
|
|
|
debug(8, "Shutting down sprite subsystem...");
|
2004-04-12 21:40:49 +00:00
|
|
|
}
|
|
|
|
|
2005-07-19 19:05:52 +00:00
|
|
|
void Sprite::loadList(int resourceId, SpriteList &spriteList) {
|
2010-10-24 22:17:44 +00:00
|
|
|
ByteArray spriteListData;
|
|
|
|
_vm->_resource->loadResource(_spriteContext, resourceId, spriteListData);
|
2004-04-12 21:40:49 +00:00
|
|
|
|
2010-10-24 22:17:44 +00:00
|
|
|
if (spriteListData.empty()) {
|
2005-07-19 19:05:52 +00:00
|
|
|
return;
|
2004-12-18 16:08:59 +00:00
|
|
|
}
|
|
|
|
|
2010-10-24 22:17:44 +00:00
|
|
|
ByteArrayReadStreamEndian readS(spriteListData, _spriteContext->isBigEndian());
|
2004-04-12 21:40:49 +00:00
|
|
|
|
2013-10-02 08:52:40 +00:00
|
|
|
uint16 spriteCount = readS.readUint16();
|
2004-04-12 21:40:49 +00:00
|
|
|
|
2005-10-10 02:42:50 +00:00
|
|
|
debug(9, "Sprites: %d", spriteCount);
|
|
|
|
|
2013-10-02 08:52:40 +00:00
|
|
|
uint16 oldSpriteCount = spriteList.size();
|
|
|
|
uint16 newSpriteCount = oldSpriteCount + spriteCount;
|
2004-04-12 21:40:49 +00:00
|
|
|
|
2010-10-19 22:29:53 +00:00
|
|
|
spriteList.resize(newSpriteCount);
|
2004-04-12 21:40:49 +00:00
|
|
|
|
2008-12-21 15:59:05 +00:00
|
|
|
bool bigHeader = _vm->getGameId() == GID_IHNM || _vm->isMacResources();
|
2005-10-11 06:08:42 +00:00
|
|
|
|
2013-10-02 08:52:40 +00:00
|
|
|
for (uint i = oldSpriteCount; i < spriteList.size(); i++) {
|
|
|
|
uint32 offset;
|
2005-10-11 06:08:42 +00:00
|
|
|
if (bigHeader)
|
2005-01-09 15:07:49 +00:00
|
|
|
offset = readS.readUint32();
|
|
|
|
else
|
|
|
|
offset = readS.readUint16();
|
2004-04-12 21:40:49 +00:00
|
|
|
|
2010-10-24 22:17:44 +00:00
|
|
|
if (offset >= spriteListData.size()) {
|
2007-08-01 02:19:05 +00:00
|
|
|
// ITE Mac demos throw this warning
|
|
|
|
warning("Sprite::loadList offset exceeded");
|
2010-10-19 22:29:53 +00:00
|
|
|
spriteList.resize(i);
|
2008-01-27 19:47:41 +00:00
|
|
|
return;
|
2005-01-09 15:07:49 +00:00
|
|
|
}
|
2004-04-12 21:40:49 +00:00
|
|
|
|
2013-10-02 08:52:40 +00:00
|
|
|
const byte *spritePointer = spriteListData.getBuffer();
|
2005-01-09 15:07:49 +00:00
|
|
|
spritePointer += offset;
|
2004-04-12 21:40:49 +00:00
|
|
|
|
2013-10-02 08:52:40 +00:00
|
|
|
const byte *spriteDataPointer;
|
|
|
|
SpriteInfo *spriteInfo = &spriteList[i];
|
2005-10-11 06:08:42 +00:00
|
|
|
if (bigHeader) {
|
2010-11-18 16:38:03 +00:00
|
|
|
Common::MemoryReadStreamEndian readS2(spritePointer, 8, _spriteContext->isBigEndian());
|
2004-04-12 21:40:49 +00:00
|
|
|
|
2005-10-07 10:44:48 +00:00
|
|
|
spriteInfo->xAlign = readS2.readSint16();
|
|
|
|
spriteInfo->yAlign = readS2.readSint16();
|
2004-04-12 21:40:49 +00:00
|
|
|
|
2005-10-07 10:44:48 +00:00
|
|
|
spriteInfo->width = readS2.readUint16();
|
|
|
|
spriteInfo->height = readS2.readUint16();
|
2005-10-07 05:31:13 +00:00
|
|
|
|
2005-10-07 10:44:48 +00:00
|
|
|
spriteDataPointer = spritePointer + readS2.pos();
|
2005-01-09 15:07:49 +00:00
|
|
|
} else {
|
2010-11-23 22:27:20 +00:00
|
|
|
Common::MemoryReadStreamEndian readS2(spritePointer, 4, false);
|
2005-10-07 05:31:13 +00:00
|
|
|
|
2005-10-07 10:44:48 +00:00
|
|
|
spriteInfo->xAlign = readS2.readSByte();
|
|
|
|
spriteInfo->yAlign = readS2.readSByte();
|
2004-04-12 21:40:49 +00:00
|
|
|
|
2005-10-07 10:44:48 +00:00
|
|
|
spriteInfo->width = readS2.readByte();
|
|
|
|
spriteInfo->height = readS2.readByte();
|
|
|
|
spriteDataPointer = spritePointer + readS2.pos();
|
2005-01-09 15:07:49 +00:00
|
|
|
}
|
2005-10-07 10:44:48 +00:00
|
|
|
|
2013-10-02 08:52:40 +00:00
|
|
|
int outputLength = spriteInfo->width * spriteInfo->height;
|
|
|
|
int inputLength = spriteListData.size() - (spriteDataPointer - spriteListData.getBuffer());
|
2010-10-19 22:29:53 +00:00
|
|
|
spriteInfo->decodedBuffer.resize(outputLength);
|
2010-10-20 22:02:33 +00:00
|
|
|
if (outputLength > 0) {
|
|
|
|
decodeRLEBuffer(spriteDataPointer, inputLength, outputLength);
|
2010-10-22 23:13:17 +00:00
|
|
|
byte *dst = &spriteInfo->decodedBuffer.front();
|
2009-01-02 16:52:38 +00:00
|
|
|
#ifdef ENABLE_IHNM
|
2010-10-20 22:02:33 +00:00
|
|
|
// IHNM sprites are upside-down, for reasons which i can only
|
|
|
|
// assume are perverse. To simplify things, flip them now. Not
|
|
|
|
// at drawing time.
|
2006-01-13 19:07:49 +00:00
|
|
|
|
2010-10-20 22:02:33 +00:00
|
|
|
if (_vm->getGameId() == GID_IHNM) {
|
|
|
|
byte *src = &_decodeBuf[spriteInfo->width * (spriteInfo->height - 1)];
|
2006-01-13 19:07:49 +00:00
|
|
|
|
2010-10-20 22:02:33 +00:00
|
|
|
for (int j = 0; j < spriteInfo->height; j++) {
|
|
|
|
memcpy(dst, src, spriteInfo->width);
|
|
|
|
src -= spriteInfo->width;
|
|
|
|
dst += spriteInfo->width;
|
|
|
|
}
|
|
|
|
} else
|
2009-01-02 16:52:38 +00:00
|
|
|
#endif
|
2010-10-20 22:02:33 +00:00
|
|
|
memcpy(dst, &_decodeBuf.front(), outputLength);
|
|
|
|
}
|
2004-04-12 21:40:49 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2010-10-19 22:29:53 +00:00
|
|
|
void Sprite::getScaledSpriteBuffer(SpriteList &spriteList, uint spriteNumber, int scale, int &width, int &height, int &xAlign, int &yAlign, const byte *&buffer) {
|
2005-01-09 15:07:49 +00:00
|
|
|
SpriteInfo *spriteInfo;
|
2008-01-10 10:34:23 +00:00
|
|
|
|
2010-10-19 22:29:53 +00:00
|
|
|
if (spriteList.size() <= spriteNumber) {
|
2008-01-10 10:34:23 +00:00
|
|
|
// this can occur in IHNM while loading a saved game from chapter 1-5 when being in the end chapter
|
2010-10-19 22:29:53 +00:00
|
|
|
warning("spriteList.size() <= spriteNumber");
|
2008-01-10 10:34:23 +00:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2010-10-19 22:29:53 +00:00
|
|
|
spriteInfo = &spriteList[spriteNumber];
|
2005-01-09 15:07:49 +00:00
|
|
|
|
|
|
|
if (scale < 256) {
|
2010-10-22 23:13:17 +00:00
|
|
|
xAlign = (spriteInfo->xAlign * scale) >> 8; //TODO: do we need to take in account sprite x&y aligns ?
|
|
|
|
yAlign = (spriteInfo->yAlign * scale) >> 8; // ????
|
2005-08-15 01:01:52 +00:00
|
|
|
height = (spriteInfo->height * scale + 0x7f) >> 8;
|
|
|
|
width = (spriteInfo->width * scale + 0x7f) >> 8;
|
2010-10-20 22:02:33 +00:00
|
|
|
size_t outLength = width * height;
|
|
|
|
if (outLength > 0) {
|
2010-10-22 23:13:17 +00:00
|
|
|
scaleBuffer(&spriteInfo->decodedBuffer.front(), spriteInfo->width, spriteInfo->height, scale, outLength);
|
2010-10-20 22:02:33 +00:00
|
|
|
buffer = &_decodeBuf.front();
|
|
|
|
} else {
|
|
|
|
buffer = NULL;
|
|
|
|
}
|
2005-01-09 15:07:49 +00:00
|
|
|
} else {
|
|
|
|
xAlign = spriteInfo->xAlign;
|
|
|
|
yAlign = spriteInfo->yAlign;
|
|
|
|
height = spriteInfo->height;
|
|
|
|
width = spriteInfo->width;
|
2010-10-22 23:13:17 +00:00
|
|
|
buffer = spriteInfo->decodedBuffer.getBuffer();
|
2004-04-12 21:40:49 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2008-12-12 20:10:00 +00:00
|
|
|
void Sprite::drawClip(const Point &spritePointer, int width, int height, const byte *spriteBuffer, bool clipToScene) {
|
|
|
|
Common::Rect clipRect = clipToScene ? _vm->_scene->getSceneClip() : _vm->getDisplayClip();
|
2004-04-12 21:40:49 +00:00
|
|
|
|
2010-10-21 20:13:25 +00:00
|
|
|
int xDstOffset, yDstOffset, xSrcOffset, ySrcOffset, xDiff, yDiff, cWidth, cHeight;
|
2005-02-18 00:00:00 +00:00
|
|
|
byte *bufRowPointer;
|
2010-10-21 20:13:25 +00:00
|
|
|
byte *bufPointer;
|
2005-02-18 00:00:00 +00:00
|
|
|
const byte *srcRowPointer;
|
2010-10-21 20:13:25 +00:00
|
|
|
const byte *srcPointer;
|
|
|
|
|
|
|
|
int backBufferPitch = _vm->_gfx->getBackBufferPitch();
|
2011-06-19 22:59:48 +00:00
|
|
|
|
2010-10-21 20:13:25 +00:00
|
|
|
//find Rects intersection
|
|
|
|
yDiff = clipRect.top - spritePointer.y;
|
|
|
|
if (yDiff > 0) {
|
|
|
|
ySrcOffset = yDiff;
|
|
|
|
yDstOffset = clipRect.top;
|
|
|
|
cHeight = height - yDiff;
|
|
|
|
} else {
|
|
|
|
ySrcOffset = 0;
|
|
|
|
yDstOffset = spritePointer.y;
|
|
|
|
cHeight = height;
|
|
|
|
}
|
2004-04-12 21:40:49 +00:00
|
|
|
|
2010-10-21 20:13:25 +00:00
|
|
|
xDiff = clipRect.left - spritePointer.x;
|
|
|
|
if (xDiff > 0) {
|
|
|
|
xSrcOffset = xDiff;
|
|
|
|
xDstOffset = clipRect.left;
|
|
|
|
cWidth = width - xDiff;
|
|
|
|
} else {
|
|
|
|
xSrcOffset = 0;
|
|
|
|
xDstOffset = spritePointer.x;
|
|
|
|
cWidth = width;
|
2005-02-18 00:00:00 +00:00
|
|
|
}
|
2010-10-21 20:13:25 +00:00
|
|
|
|
|
|
|
yDiff = yDstOffset + cHeight - clipRect.bottom;
|
|
|
|
if (yDiff > 0) {
|
|
|
|
cHeight -= yDiff;
|
2004-04-12 21:40:49 +00:00
|
|
|
}
|
2005-10-10 02:02:58 +00:00
|
|
|
|
2010-10-21 20:13:25 +00:00
|
|
|
xDiff = xDstOffset + cWidth - clipRect.right;
|
|
|
|
if (xDiff > 0) {
|
|
|
|
cWidth -= xDiff;
|
|
|
|
}
|
2004-04-12 21:40:49 +00:00
|
|
|
|
2010-10-21 20:13:25 +00:00
|
|
|
if ((cHeight <= 0) || (cWidth <= 0)) {
|
|
|
|
//no intersection
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
bufRowPointer = _vm->_gfx->getBackBufferPixels() + backBufferPitch * yDstOffset + xDstOffset;
|
|
|
|
srcRowPointer = spriteBuffer + width * ySrcOffset + xSrcOffset;
|
2011-06-19 22:59:48 +00:00
|
|
|
|
2010-10-21 20:13:25 +00:00
|
|
|
// validate src, dst buffers
|
|
|
|
assert(_vm->_gfx->getBackBufferPixels() <= bufRowPointer);
|
2011-06-19 22:59:48 +00:00
|
|
|
assert((_vm->_gfx->getBackBufferPixels() + (_vm->getDisplayInfo().width * _vm->getDisplayInfo().height)) >=
|
2010-10-21 20:13:25 +00:00
|
|
|
(byte *)(bufRowPointer + backBufferPitch * (cHeight - 1) + cWidth));
|
|
|
|
assert((const byte *)spriteBuffer <= srcRowPointer);
|
|
|
|
assert(((const byte *)spriteBuffer + (width * height)) >= (const byte *)(srcRowPointer + width * (cHeight - 1) + cWidth));
|
|
|
|
|
|
|
|
const byte *srcPointerFinish2 = srcRowPointer + width * cHeight;
|
|
|
|
for (;;) {
|
|
|
|
srcPointer = srcRowPointer;
|
|
|
|
bufPointer = bufRowPointer;
|
|
|
|
const byte *srcPointerFinish = srcRowPointer + cWidth;
|
|
|
|
for (;;) {
|
|
|
|
if (*srcPointer != 0) {
|
|
|
|
*bufPointer = *srcPointer;
|
|
|
|
}
|
|
|
|
srcPointer++;
|
|
|
|
bufPointer++;
|
|
|
|
if (srcPointer == srcPointerFinish) {
|
|
|
|
break;
|
2004-04-12 21:40:49 +00:00
|
|
|
}
|
|
|
|
}
|
2005-01-18 23:15:41 +00:00
|
|
|
srcRowPointer += width;
|
2010-10-21 20:13:25 +00:00
|
|
|
if (srcRowPointer == srcPointerFinish2) {
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
bufRowPointer += backBufferPitch;
|
2004-04-12 21:40:49 +00:00
|
|
|
}
|
2008-12-07 18:49:35 +00:00
|
|
|
|
2010-10-21 20:13:25 +00:00
|
|
|
_vm->_render->addDirtyRect(Common::Rect(xDstOffset, yDstOffset, xDstOffset + cWidth, yDstOffset + cHeight));
|
2005-02-18 00:00:00 +00:00
|
|
|
}
|
|
|
|
|
2010-10-19 22:29:53 +00:00
|
|
|
void Sprite::draw(SpriteList &spriteList, uint spriteNumber, const Point &screenCoord, int scale, bool clipToScene) {
|
2008-11-29 18:01:16 +00:00
|
|
|
const byte *spriteBuffer = NULL;
|
|
|
|
int width = 0;
|
|
|
|
int height = 0;
|
|
|
|
int xAlign = 0;
|
|
|
|
int yAlign = 0;
|
2005-02-18 00:00:00 +00:00
|
|
|
Point spritePointer;
|
2005-07-08 16:43:36 +00:00
|
|
|
|
2005-02-18 00:00:00 +00:00
|
|
|
getScaledSpriteBuffer(spriteList, spriteNumber, scale, width, height, xAlign, yAlign, spriteBuffer);
|
2005-07-29 17:58:00 +00:00
|
|
|
|
2005-02-18 00:00:00 +00:00
|
|
|
spritePointer.x = screenCoord.x + xAlign;
|
|
|
|
spritePointer.y = screenCoord.y + yAlign;
|
2005-10-07 05:31:13 +00:00
|
|
|
|
2008-12-12 20:10:00 +00:00
|
|
|
drawClip(spritePointer, width, height, spriteBuffer, clipToScene);
|
2004-04-12 21:40:49 +00:00
|
|
|
}
|
|
|
|
|
2010-10-19 22:29:53 +00:00
|
|
|
void Sprite::draw(SpriteList &spriteList, uint spriteNumber, const Rect &screenRect, int scale, bool clipToScene) {
|
2008-11-29 18:01:16 +00:00
|
|
|
const byte *spriteBuffer = NULL;
|
|
|
|
int width = 0;
|
|
|
|
int height = 0;
|
|
|
|
int xAlign = 0;
|
|
|
|
int spw;
|
|
|
|
int yAlign = 0;
|
|
|
|
int sph;
|
2005-04-22 14:11:04 +00:00
|
|
|
Point spritePointer;
|
2005-07-29 17:58:00 +00:00
|
|
|
|
2005-04-22 14:11:04 +00:00
|
|
|
getScaledSpriteBuffer(spriteList, spriteNumber, scale, width, height, xAlign, yAlign, spriteBuffer);
|
|
|
|
spw = (screenRect.width() - width) / 2;
|
|
|
|
sph = (screenRect.height() - height) / 2;
|
|
|
|
if (spw < 0) {
|
|
|
|
spw = 0;
|
|
|
|
}
|
|
|
|
if (sph < 0) {
|
|
|
|
sph = 0;
|
|
|
|
}
|
|
|
|
spritePointer.x = screenRect.left + xAlign + spw;
|
|
|
|
spritePointer.y = screenRect.top + yAlign + sph;
|
2008-12-12 20:10:00 +00:00
|
|
|
drawClip(spritePointer, width, height, spriteBuffer, clipToScene);
|
2005-04-22 14:11:04 +00:00
|
|
|
}
|
|
|
|
|
2010-10-19 22:29:53 +00:00
|
|
|
bool Sprite::hitTest(SpriteList &spriteList, uint spriteNumber, const Point &screenCoord, int scale, const Point &testPoint) {
|
2008-11-29 18:01:16 +00:00
|
|
|
const byte *spriteBuffer = NULL;
|
2005-01-18 23:15:41 +00:00
|
|
|
int i, j;
|
|
|
|
const byte *srcRowPointer;
|
2008-11-29 18:01:16 +00:00
|
|
|
int width = 0;
|
|
|
|
int height = 0;
|
|
|
|
int xAlign = 0;
|
|
|
|
int yAlign = 0;
|
2005-01-18 23:15:41 +00:00
|
|
|
Point spritePointer;
|
|
|
|
|
|
|
|
getScaledSpriteBuffer(spriteList, spriteNumber, scale, width, height, xAlign, yAlign, spriteBuffer);
|
|
|
|
|
|
|
|
spritePointer.x = screenCoord.x + xAlign;
|
|
|
|
spritePointer.y = screenCoord.y + yAlign;
|
|
|
|
|
2005-04-16 16:55:35 +00:00
|
|
|
if ((testPoint.y < spritePointer.y) || (testPoint.y >= spritePointer.y + height)) {
|
2005-01-18 23:15:41 +00:00
|
|
|
return false;
|
|
|
|
}
|
2005-04-16 16:55:35 +00:00
|
|
|
if ((testPoint.x < spritePointer.x) || (testPoint.x >= spritePointer.x + width)) {
|
2005-01-18 23:15:41 +00:00
|
|
|
return false;
|
|
|
|
}
|
|
|
|
i = testPoint.y - spritePointer.y;
|
|
|
|
j = testPoint.x - spritePointer.x;
|
|
|
|
srcRowPointer = spriteBuffer + j + i * width;
|
2005-07-29 17:58:00 +00:00
|
|
|
return *srcRowPointer != 0;
|
2005-01-18 23:15:41 +00:00
|
|
|
}
|
|
|
|
|
2010-10-19 22:29:53 +00:00
|
|
|
void Sprite::drawOccluded(SpriteList &spriteList, uint spriteNumber, const Point &screenCoord, int scale, int depth) {
|
2008-11-29 18:01:16 +00:00
|
|
|
const byte *spriteBuffer = NULL;
|
2004-04-12 21:40:49 +00:00
|
|
|
int x, y;
|
2005-07-08 16:56:03 +00:00
|
|
|
byte *destRowPointer;
|
|
|
|
const byte *sourceRowPointer;
|
|
|
|
const byte *sourcePointer;
|
|
|
|
byte *destPointer;
|
|
|
|
byte *maskPointer;
|
2008-12-03 11:05:07 +00:00
|
|
|
int width = 0;
|
2008-11-29 18:01:16 +00:00
|
|
|
int height = 0;
|
|
|
|
int xAlign = 0;
|
|
|
|
int yAlign = 0;
|
2004-04-12 21:40:49 +00:00
|
|
|
|
2005-07-08 16:56:03 +00:00
|
|
|
ClipData clipData;
|
2004-04-12 21:40:49 +00:00
|
|
|
|
2004-05-01 16:15:55 +00:00
|
|
|
// BG mask variables
|
2004-12-28 21:27:18 +00:00
|
|
|
int maskWidth;
|
|
|
|
int maskHeight;
|
|
|
|
byte *maskBuffer;
|
2005-07-08 16:56:03 +00:00
|
|
|
byte *maskRowPointer;
|
|
|
|
int maskZ;
|
|
|
|
|
2004-08-04 20:28:57 +00:00
|
|
|
if (!_vm->_scene->isBGMaskPresent()) {
|
2008-12-12 14:23:02 +00:00
|
|
|
draw(spriteList, spriteNumber, screenCoord, scale);
|
2005-07-08 16:56:03 +00:00
|
|
|
return;
|
2004-04-12 21:40:49 +00:00
|
|
|
}
|
|
|
|
|
2010-10-23 21:56:16 +00:00
|
|
|
_vm->_scene->getBGMaskInfo(maskWidth, maskHeight, maskBuffer);
|
2004-04-12 21:40:49 +00:00
|
|
|
|
2005-01-09 15:07:49 +00:00
|
|
|
getScaledSpriteBuffer(spriteList, spriteNumber, scale, width, height, xAlign, yAlign, spriteBuffer);
|
2004-04-25 15:14:46 +00:00
|
|
|
|
2005-07-08 16:56:03 +00:00
|
|
|
clipData.destPoint.x = screenCoord.x + xAlign;
|
|
|
|
clipData.destPoint.y = screenCoord.y + yAlign;
|
2005-07-29 17:58:00 +00:00
|
|
|
|
2005-07-08 16:56:03 +00:00
|
|
|
clipData.sourceRect.left = 0;
|
|
|
|
clipData.sourceRect.top = 0;
|
|
|
|
clipData.sourceRect.right = width;
|
|
|
|
clipData.sourceRect.bottom = height;
|
2004-04-12 21:40:49 +00:00
|
|
|
|
2008-12-12 20:10:00 +00:00
|
|
|
clipData.destRect = _vm->_scene->getSceneClip();
|
2004-04-12 21:40:49 +00:00
|
|
|
|
2005-07-08 16:56:03 +00:00
|
|
|
if (!clipData.calcClip()) {
|
|
|
|
return;
|
2004-04-12 21:40:49 +00:00
|
|
|
}
|
|
|
|
|
2004-05-01 16:15:55 +00:00
|
|
|
// Finally, draw the occluded sprite
|
2005-07-29 17:58:00 +00:00
|
|
|
|
2006-01-13 19:07:49 +00:00
|
|
|
sourceRowPointer = spriteBuffer + clipData.drawSource.x + (clipData.drawSource.y * width);
|
2008-12-06 18:23:34 +00:00
|
|
|
destRowPointer = _vm->_gfx->getBackBufferPixels() + clipData.drawDest.x + (clipData.drawDest.y * _vm->_gfx->getBackBufferPitch());
|
2005-07-09 16:23:45 +00:00
|
|
|
maskRowPointer = maskBuffer + clipData.drawDest.x + (clipData.drawDest.y * maskWidth);
|
2005-07-08 16:56:03 +00:00
|
|
|
|
2005-07-09 16:23:45 +00:00
|
|
|
for (y = 0; y < clipData.drawHeight; y++) {
|
2005-07-08 16:56:03 +00:00
|
|
|
sourcePointer = sourceRowPointer;
|
|
|
|
destPointer = destRowPointer;
|
|
|
|
maskPointer = maskRowPointer;
|
2005-07-09 16:23:45 +00:00
|
|
|
for (x = 0; x < clipData.drawWidth; x++) {
|
2005-07-08 16:56:03 +00:00
|
|
|
if (*sourcePointer != 0) {
|
|
|
|
maskZ = *maskPointer & SPRITE_ZMASK;
|
|
|
|
if (maskZ > depth) {
|
|
|
|
*destPointer = *sourcePointer;
|
2004-04-12 21:40:49 +00:00
|
|
|
}
|
|
|
|
}
|
2005-07-08 16:56:03 +00:00
|
|
|
sourcePointer++;
|
|
|
|
destPointer++;
|
|
|
|
maskPointer++;
|
2004-04-12 21:40:49 +00:00
|
|
|
}
|
2008-12-06 18:23:34 +00:00
|
|
|
destRowPointer += _vm->_gfx->getBackBufferPitch();
|
2005-07-08 16:56:03 +00:00
|
|
|
maskRowPointer += maskWidth;
|
|
|
|
sourceRowPointer += width;
|
2004-04-12 21:40:49 +00:00
|
|
|
}
|
2008-12-07 18:49:35 +00:00
|
|
|
|
2009-01-01 15:06:43 +00:00
|
|
|
_vm->_render->addDirtyRect(Common::Rect(clipData.drawSource.x, clipData.drawSource.y,
|
2008-12-12 14:23:02 +00:00
|
|
|
clipData.drawSource.x + width, clipData.drawSource.y + height));
|
2004-04-12 21:40:49 +00:00
|
|
|
}
|
|
|
|
|
2005-01-09 15:07:49 +00:00
|
|
|
void Sprite::decodeRLEBuffer(const byte *inputBuffer, size_t inLength, size_t outLength) {
|
2004-04-12 21:40:49 +00:00
|
|
|
int bg_runcount;
|
|
|
|
int fg_runcount;
|
2005-01-09 15:07:49 +00:00
|
|
|
byte *outPointer;
|
|
|
|
byte *outPointerEnd;
|
2004-04-12 21:40:49 +00:00
|
|
|
int c;
|
|
|
|
|
2010-10-20 22:02:33 +00:00
|
|
|
_decodeBuf.resize(outLength);
|
|
|
|
outPointer = &_decodeBuf.front();
|
|
|
|
outPointerEnd = &_decodeBuf.back();
|
2004-04-12 21:40:49 +00:00
|
|
|
|
2010-10-20 22:02:33 +00:00
|
|
|
memset(outPointer, 0, _decodeBuf.size());
|
2004-04-12 21:40:49 +00:00
|
|
|
|
2010-11-18 16:38:03 +00:00
|
|
|
Common::MemoryReadStream readS(inputBuffer, inLength);
|
2005-01-04 17:15:53 +00:00
|
|
|
|
2005-06-02 22:34:55 +00:00
|
|
|
while (!readS.eos() && (outPointer < outPointerEnd)) {
|
2005-01-04 17:15:53 +00:00
|
|
|
bg_runcount = readS.readByte();
|
2008-09-15 09:17:18 +00:00
|
|
|
if (readS.eos())
|
|
|
|
break;
|
2005-01-04 17:15:53 +00:00
|
|
|
fg_runcount = readS.readByte();
|
2004-04-12 21:40:49 +00:00
|
|
|
|
2005-06-02 22:14:57 +00:00
|
|
|
for (c = 0; c < bg_runcount && !readS.eos(); c++) {
|
2005-01-09 15:07:49 +00:00
|
|
|
*outPointer = (byte) 0;
|
|
|
|
if (outPointer < outPointerEnd)
|
|
|
|
outPointer++;
|
2004-04-12 21:40:49 +00:00
|
|
|
else
|
2005-01-09 15:07:49 +00:00
|
|
|
return;
|
2004-04-12 21:40:49 +00:00
|
|
|
}
|
|
|
|
|
2005-06-02 22:14:57 +00:00
|
|
|
for (c = 0; c < fg_runcount && !readS.eos(); c++) {
|
2005-01-09 15:07:49 +00:00
|
|
|
*outPointer = readS.readByte();
|
2008-09-15 09:17:18 +00:00
|
|
|
if (readS.eos())
|
|
|
|
break;
|
2005-01-09 15:07:49 +00:00
|
|
|
if (outPointer < outPointerEnd)
|
|
|
|
outPointer++;
|
2004-04-12 21:40:49 +00:00
|
|
|
else
|
2005-01-09 15:07:49 +00:00
|
|
|
return;
|
2004-04-12 21:40:49 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2010-10-20 22:02:33 +00:00
|
|
|
void Sprite::scaleBuffer(const byte *src, int width, int height, int scale, size_t outLength) {
|
2004-12-21 16:12:03 +00:00
|
|
|
byte skip = 256 - scale; // skip factor
|
|
|
|
byte vskip = 0x80, hskip;
|
2010-10-20 22:02:33 +00:00
|
|
|
|
|
|
|
_decodeBuf.resize(outLength);
|
|
|
|
byte *dst = &_decodeBuf.front();
|
2011-06-19 22:59:48 +00:00
|
|
|
|
2010-10-20 22:02:33 +00:00
|
|
|
memset(dst, 0, _decodeBuf.size());
|
2004-12-21 16:12:03 +00:00
|
|
|
|
|
|
|
for (int i = 0; i < height; i++) {
|
|
|
|
vskip += skip;
|
|
|
|
|
2005-05-08 21:49:52 +00:00
|
|
|
if (vskip < skip) { // We had an overflow
|
2004-12-21 16:12:03 +00:00
|
|
|
src += width;
|
|
|
|
} else {
|
|
|
|
hskip = 0x80;
|
|
|
|
|
|
|
|
for (int j = 0; j < width; j++) {
|
|
|
|
*dst++ = *src++;
|
2005-07-29 17:58:00 +00:00
|
|
|
|
2004-12-21 16:12:03 +00:00
|
|
|
hskip += skip;
|
|
|
|
if (hskip < skip) // overflow
|
|
|
|
dst--;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2004-04-12 21:40:49 +00:00
|
|
|
} // End of namespace Saga
|