From ade8eec8cf853c8f5fe16cbf410440e76e0ac23e Mon Sep 17 00:00:00 2001 From: Benjamin Haisch Date: Wed, 17 Sep 2008 10:59:23 +0000 Subject: TOLTECS: Moved sprite drawing code to sprite.cpp --- engines/toltecs/sprite.cpp | 535 +++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 535 insertions(+) create mode 100644 engines/toltecs/sprite.cpp (limited to 'engines/toltecs/sprite.cpp') diff --git a/engines/toltecs/sprite.cpp b/engines/toltecs/sprite.cpp new file mode 100644 index 0000000000..b9f8ffe0a4 --- /dev/null +++ b/engines/toltecs/sprite.cpp @@ -0,0 +1,535 @@ +/* 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/events.h" +#include "common/keyboard.h" +#include "common/file.h" +#include "common/savefile.h" +#include "common/config-manager.h" + +#include "base/plugins.h" +#include "base/version.h" + +#include "graphics/cursorman.h" + +#include "sound/mixer.h" + +#include "toltecs/toltecs.h" +#include "toltecs/palette.h" +#include "toltecs/resource.h" +#include "toltecs/screen.h" +#include "toltecs/script.h" +#include "toltecs/segmap.h" + +namespace Toltecs { + +class SpriteReader : public SpriteFilter { +public: + SpriteReader(byte *source, SpriteDrawItem *sprite) : SpriteFilter(sprite), _source(source) { + _curWidth = _sprite->origWidth; + _curHeight = _sprite->origHeight; + } + SpriteReaderStatus readPacket(PixelPacket &packet) { + if (_sprite->flags & 0x40) { + // shadow sprite + packet.count = _source[0] & 0x7F; + if (_source[0] & 0x80) + packet.pixel = 1; + else + packet.pixel = 0; + _source++; + } else if (_sprite->flags & 0x10) { + // 256-color sprite + packet.pixel = *_source++; + packet.count = *_source++; + } else { + // 16-color sprite + packet.count = _source[0] & 0x0F; + packet.pixel = (_source[0] & 0xF0) >> 4; + _source++; + } + _curWidth -= packet.count; + if (_curWidth <= 0) { + _curHeight--; + if (_curHeight == 0) { + return kSrsEndOfSprite; + } else { + _curWidth = _sprite->origWidth; + return kSrsEndOfLine; + } + } else { + return kSrsPixelsLeft; + } + } + byte *getSource() { + return _source; + } + void setSource(byte *source) { + _source = source; + _curHeight++; + } +protected: + byte *_source; + int16 _curWidth, _curHeight; +}; + +class SpriteFilterScaleDown : public SpriteFilter { +public: + SpriteFilterScaleDown(SpriteDrawItem *sprite, SpriteReader *reader) : SpriteFilter(sprite), _reader(reader) { + _height = _sprite->height; + _yerror = _sprite->yerror; + _origHeight = _sprite->origHeight; + _scalerStatus = 0; + } + SpriteReaderStatus readPacket(PixelPacket &packet) { + SpriteReaderStatus status; + if (_scalerStatus == 0) { + _xerror = _sprite->xdelta; + _yerror -= 100; + while (_yerror <= 0) { + do { + status = _reader->readPacket(packet); + } while (status == kSrsPixelsLeft); + _yerror += _sprite->ydelta - 100; + } + if (status == kSrsEndOfSprite) + return kSrsEndOfSprite; + _scalerStatus = 1; + } + if (_scalerStatus == 1) { + status = _reader->readPacket(packet); + byte updcount = packet.count; + while (updcount--) { + _xerror -= 100; + if (_xerror <= 0) { + if (packet.count > 0) + packet.count--; + _xerror += _sprite->xdelta; + } + } + if (status == kSrsEndOfLine) { + if (--_height == 0) + return kSrsEndOfSprite; + _scalerStatus = 0; + return kSrsEndOfLine; + } + } + return kSrsPixelsLeft; + } +protected: + SpriteReader *_reader; + int16 _xerror, _yerror; + int16 _height; + int16 _origHeight; + int _scalerStatus; +}; + +class SpriteFilterScaleUp : public SpriteFilter { +public: + SpriteFilterScaleUp(SpriteDrawItem *sprite, SpriteReader *reader) : SpriteFilter(sprite), _reader(reader) { + _height = _sprite->height; + _yerror = _sprite->yerror; + _origHeight = _sprite->origHeight; + _scalerStatus = 0; + } + SpriteReaderStatus readPacket(PixelPacket &packet) { + SpriteReaderStatus status; + if (_scalerStatus == 0) { + _xerror = _sprite->xdelta; + _sourcep = _reader->getSource(); + _scalerStatus = 1; + } + if (_scalerStatus == 1) { + status = _reader->readPacket(packet); + byte updcount = packet.count; + while (updcount--) { + _xerror -= 100; + if (_xerror <= 0) { + packet.count++; + _xerror += _sprite->xdelta; + } + } + if (status == kSrsEndOfLine) { + if (--_height == 0) + return kSrsEndOfSprite; + _yerror -= 100; + if (_yerror <= 0) { + _reader->setSource(_sourcep); + _yerror += _sprite->ydelta + 100; + } + _scalerStatus = 0; + return kSrsEndOfLine; + } + } + return kSrsPixelsLeft; + } +protected: + SpriteReader *_reader; + byte *_sourcep; + int16 _xerror, _yerror; + int16 _height; + int16 _origHeight; + int _scalerStatus; +}; + +void Screen::addDrawRequest(const DrawRequest &drawRequest) { + + int16 scaleValueX, scaleValueY; + int16 xoffs, yoffs; + byte *spriteData; + int16 frameNum; + + SpriteDrawItem sprite; + memset(&sprite, 0, sizeof(SpriteDrawItem)); + + if (drawRequest.flags == 0xFFFF) + return; + + sprite.flags = 0; + sprite.baseColor = drawRequest.baseColor; + sprite.x = drawRequest.x; + sprite.y = drawRequest.y; + sprite.ybottom = drawRequest.y; + sprite.resIndex = drawRequest.resIndex; + + spriteData = _vm->_res->load(drawRequest.resIndex); + + if (drawRequest.flags & 0x1000) { + sprite.flags |= 4; + } + + if (drawRequest.flags & 0x2000) { + sprite.flags |= 0x10; + } + + if (drawRequest.flags & 0x4000) { + sprite.flags |= 0x40; + } + + frameNum = drawRequest.flags & 0x0FFF; + + // First initialize the sprite item with the values from the sprite resource + + SpriteFrameEntry spriteFrameEntry(spriteData + frameNum * 12); + + if (spriteFrameEntry.w == 0 || spriteFrameEntry.h == 0) + return; + + sprite.offset = spriteFrameEntry.offset; + + sprite.width = spriteFrameEntry.w; + sprite.height = spriteFrameEntry.h; + + sprite.origWidth = spriteFrameEntry.w; + sprite.origHeight = spriteFrameEntry.h; + + if (drawRequest.flags & 0x1000) { + xoffs = spriteFrameEntry.w - spriteFrameEntry.x; + } else { + xoffs = spriteFrameEntry.x; + } + + yoffs = spriteFrameEntry.y; + + // If the sprite should be scaled we need to initialize some values now + + if (drawRequest.scaling != 0) { + + byte scaleValue = ABS(drawRequest.scaling); + + scaleValueX = scaleValue * sprite.origWidth; + sprite.xdelta = (10000 * sprite.origWidth) / scaleValueX; + scaleValueX /= 100; + + scaleValueY = scaleValue * sprite.origHeight; + sprite.ydelta = (10000 * sprite.origHeight) / scaleValueY; + scaleValueY /= 100; + + if (drawRequest.scaling > 0) { + sprite.flags |= 2; + sprite.width = sprite.origWidth + scaleValueX; + sprite.height = sprite.origHeight + scaleValueY; + xoffs += (xoffs * scaleValue) / 100; + yoffs += (yoffs * scaleValue) / 100; + } else { + sprite.flags |= 1; + sprite.width = sprite.origWidth - scaleValueX; + sprite.height = sprite.origHeight - 1 - scaleValueY; + if (sprite.width <= 0 || sprite.height <= 0) + return; + xoffs -= (xoffs * scaleValue) / 100; + yoffs -= (yoffs * scaleValue) / 100; + } + + } + + sprite.x -= xoffs; + sprite.y -= yoffs; + + sprite.yerror = sprite.ydelta; + + // Now we check if the sprite needs to be clipped + + // Clip Y + if (sprite.y - _vm->_cameraY < 0) { + + int16 clipHeight = ABS(sprite.y - _vm->_cameraY); + int16 chopHeight, skipHeight, lineWidth; + byte *spriteFrameData; + + sprite.height -= clipHeight; + if (sprite.height <= 0) + return; + + sprite.y = _vm->_cameraY; + + // If the sprite is scaled + if (sprite.flags & 3) { + chopHeight = sprite.ydelta; + skipHeight = clipHeight; + if ((sprite.flags & 2) == 0) { + do { + chopHeight -= 100; + if (chopHeight <= 0) { + skipHeight++; + chopHeight += sprite.ydelta; + } else { + clipHeight--; + } + } while (clipHeight > 0); + } else { + do { + chopHeight -= 100; + if (chopHeight < 0) { + skipHeight--; + chopHeight += sprite.ydelta + 100; + } + clipHeight--; + } while (clipHeight > 0); + } + sprite.yerror = chopHeight; + } + + spriteFrameData = spriteData + sprite.offset; + + // Now the sprite's offset is adjusted to point to the starting line + if ((sprite.flags & 0x10) == 0) { + while (clipHeight--) { + lineWidth = 0; + while (lineWidth _cameraY - _vm->_cameraHeight > 0) + sprite.height -= sprite.y + sprite.height - _vm->_cameraY - _vm->_cameraHeight; + if (sprite.height <= 0) + return; + + sprite.skipX = 0; + + if (drawRequest.flags & 0x1000) { + // Left border + if (sprite.x - _vm->_cameraX < 0) { + sprite.width -= ABS(sprite.x - _vm->_cameraX); + sprite.x = _vm->_cameraX; + } + // Right border + if (sprite.x + sprite.width - _vm->_cameraX - 640 > 0) { + sprite.flags |= 8; + sprite.skipX = sprite.x + sprite.width - _vm->_cameraX - 640; + sprite.width -= sprite.skipX; + } + } else { + // Left border + if (sprite.x - _vm->_cameraX < 0) { + sprite.flags |= 8; + sprite.skipX = ABS(sprite.x - _vm->_cameraX); + sprite.width -= sprite.skipX; + sprite.x = _vm->_cameraX; + } + // Right border + if (sprite.x + sprite.width - _vm->_cameraX - 640 > 0) { + sprite.flags |= 8; + sprite.width -= sprite.x + sprite.width - _vm->_cameraX - 640; + } + } + + if (sprite.width <= 0) + return; + + // Add sprite sorted by priority + Common::List::iterator iter = _spriteDrawList.begin(); + while (iter != _spriteDrawList.end() && (*iter).ybottom <= sprite.ybottom) { + iter++; + } + _spriteDrawList.insert(iter, sprite); + +} + +void Screen::drawSprite(SpriteDrawItem *sprite) { + + debug(0, "Screen::drawSprite() x = %d; y = %d; flags = %04X; resIndex = %d; offset = %08X; drawX = %d; drawY = %d", + sprite->x, sprite->y, sprite->flags, sprite->resIndex, sprite->offset, + sprite->x - _vm->_cameraX, sprite->y - _vm->_cameraY); + debug(0, "Screen::drawSprite() width = %d; height = %d; origWidth = %d; origHeight = %d", + sprite->width, sprite->height, sprite->origWidth, sprite->origHeight); + + byte *source = _vm->_res->load(sprite->resIndex) + sprite->offset; + byte *dest = _frontScreen + (sprite->x - _vm->_cameraX) + (sprite->y - _vm->_cameraY) * 640; + + SpriteReader spriteReader(source, sprite); + + if (sprite->flags & 0x40) { + // Shadow sprites + if (sprite->flags & 1) { + SpriteFilterScaleDown spriteScaler(sprite, &spriteReader); + drawSpriteCore(dest, spriteScaler, sprite); + } else if (sprite->flags & 2) { + SpriteFilterScaleUp spriteScaler(sprite, &spriteReader); + drawSpriteCore(dest, spriteScaler, sprite); + } else { + drawSpriteCore(dest, spriteReader, sprite); + } + } else if (sprite->flags & 0x10) { + // 256 color sprite + drawSpriteCore(dest, spriteReader, sprite); + } else { + // 16 color sprite + if (sprite->flags & 1) { + SpriteFilterScaleDown spriteScaler(sprite, &spriteReader); + drawSpriteCore(dest, spriteScaler, sprite); + } else if (sprite->flags & 2) { + SpriteFilterScaleUp spriteScaler(sprite, &spriteReader); + drawSpriteCore(dest, spriteScaler, sprite); + } else { + drawSpriteCore(dest, spriteReader, sprite); + } + } + + debug(0, "Screen::drawSprite() ok"); + +} + +void Screen::drawSpriteCore(byte *dest, SpriteFilter &reader, SpriteDrawItem *sprite) { + + int16 destInc; + + if (sprite->flags & 4) { + destInc = -1; + dest += sprite->width; + } else { + destInc = 1; + } + + SpriteReaderStatus status; + PixelPacket packet; + + byte *destp = dest; + int16 skipX = sprite->skipX; + + int16 w = sprite->width; + int16 h = sprite->height; + + do { + status = reader.readPacket(packet); + + if (skipX > 0) { + while (skipX > 0) { + skipX -= packet.count; + if (skipX < 0) { + packet.count = ABS(skipX); + break; + } + status = reader.readPacket(packet); + } + } + + if (w - packet.count < 0) + packet.count = w; + + w -= packet.count; + + if (((sprite->flags & 0x40) && (packet.pixel != 0)) || + ((sprite->flags & 0x10) && (packet.pixel != 0xFF)) || + !(sprite->flags & 0x10) && (packet.pixel != 0)) + { + if (sprite->flags & 0x40) { + while (packet.count--) { + *dest = _vm->_palette->getColorTransPixel(*dest); + dest += destInc; + } + } else { + if (sprite->flags & 0x10) { + packet.pixel = ((packet.pixel << 4) & 0xF0) | ((packet.pixel >> 4) & 0x0F); + } else { + packet.pixel += sprite->baseColor - 1; + } + while (packet.count--) { + *dest = packet.pixel; + dest += destInc; + } + } + } else { + dest += packet.count * destInc; + } + + if (status == kSrsEndOfLine || w <= 0) { + if (w <= 0) { + while (status == kSrsPixelsLeft) { + status = reader.readPacket(packet); + } + } + dest = destp + 640; + destp = dest; + skipX = sprite->skipX; + w = sprite->width; + h--; + } + + } while (status != kSrsEndOfSprite && h > 0); + +} + +void Screen::drawSprites() { + for (Common::List::iterator iter = _spriteDrawList.begin(); iter != _spriteDrawList.end(); iter++) { + SpriteDrawItem *sprite = &(*iter); + drawSprite(sprite); + _vm->_segmap->restoreMasksBySprite(sprite); + } +} + +} // End of namespace Toltecs -- cgit v1.2.3