diff options
Diffstat (limited to 'engines')
-rw-r--r-- | engines/director/frame.cpp | 760 | ||||
-rw-r--r-- | engines/director/frame.h | 146 | ||||
-rw-r--r-- | engines/director/lingo/lingo-the.cpp | 1 | ||||
-rw-r--r-- | engines/director/module.mk | 2 | ||||
-rw-r--r-- | engines/director/score.cpp | 784 | ||||
-rw-r--r-- | engines/director/score.h | 217 | ||||
-rw-r--r-- | engines/director/sprite.cpp | 85 | ||||
-rw-r--r-- | engines/director/sprite.h | 137 |
8 files changed, 1135 insertions, 997 deletions
diff --git a/engines/director/frame.cpp b/engines/director/frame.cpp new file mode 100644 index 0000000000..abb880a6cf --- /dev/null +++ b/engines/director/frame.cpp @@ -0,0 +1,760 @@ +/* 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/system.h" +#include "graphics/macgui/macwindowmanager.h" +#include "image/bmp.h" + +#include "director/director.h" +#include "director/frame.h" +#include "director/images.h" +#include "director/score.h" +#include "director/sprite.h" + +namespace Director { + +Frame::Frame(DirectorEngine *vm) { + _vm = vm; + _transDuration = 0; + _transType = kTransNone; + _transArea = 0; + _transChunkSize = 0; + _tempo = 0; + + _sound1 = 0; + _sound2 = 0; + _soundType1 = 0; + _soundType2 = 0; + + _actionId = 0; + _skipFrameFlag = 0; + _blend = 0; + + _sprites.resize(CHANNEL_COUNT); + + for (uint16 i = 0; i < _sprites.size(); i++) { + Sprite *sp = new Sprite(); + _sprites[i] = sp; + } +} + +Frame::Frame(const Frame &frame) { + _vm = frame._vm; + _actionId = frame._actionId; + _transArea = frame._transArea; + _transDuration = frame._transDuration; + _transType = frame._transType; + _transChunkSize = frame._transChunkSize; + _tempo = frame._tempo; + _sound1 = frame._sound1; + _sound2 = frame._sound2; + _soundType1 = frame._soundType1; + _soundType2 = frame._soundType2; + _skipFrameFlag = frame._skipFrameFlag; + _blend = frame._blend; + _palette = new PaletteInfo(); + + _sprites.resize(CHANNEL_COUNT); + + for (uint16 i = 0; i < CHANNEL_COUNT; i++) { + _sprites[i] = new Sprite(*frame._sprites[i]); + } +} + +Frame::~Frame() { + delete _palette; +} + +void Frame::readChannel(Common::SeekableSubReadStreamEndian &stream, uint16 offset, uint16 size) { + if (offset >= 32) { + if (size <= 16) + readSprite(stream, offset, size); + else { + //read > 1 sprites channel + while (size > 16) { + byte spritePosition = (offset - 32) / 16; + uint16 nextStart = (spritePosition + 1) * 16 + 32; + uint16 needSize = nextStart - offset; + readSprite(stream, offset, needSize); + offset += needSize; + size -= needSize; + } + readSprite(stream, offset, size); + } + } else { + readMainChannels(stream, offset, size); + } +} + +void Frame::readMainChannels(Common::SeekableSubReadStreamEndian &stream, uint16 offset, uint16 size) { + uint16 finishPosition = offset + size; + + while (offset < finishPosition) { + switch(offset) { + case kScriptIdPosition: + _actionId = stream.readByte(); + offset++; + break; + case kSoundType1Position: + _soundType1 = stream.readByte(); + offset++; + break; + case kTransFlagsPosition: { + uint8 transFlags = stream.readByte(); + if (transFlags & 0x80) + _transArea = 1; + else + _transArea = 0; + _transDuration = transFlags & 0x7f; + offset++; + } + break; + case kTransChunkSizePosition: + _transChunkSize = stream.readByte(); + offset++; + break; + case kTempoPosition: + _tempo = stream.readByte(); + offset++; + break; + case kTransTypePosition: + _transType = static_cast<TransitionType>(stream.readByte()); + offset++; + break; + case kSound1Position: + _sound1 = stream.readUint16(); + offset+=2; + break; + case kSkipFrameFlagsPosition: + _skipFrameFlag = stream.readByte(); + offset++; + break; + case kBlendPosition: + _blend = stream.readByte(); + offset++; + break; + case kSound2Position: + _sound2 = stream.readUint16(); + offset += 2; + break; + case kSound2TypePosition: + _soundType2 = stream.readByte(); + offset += 1; + break; + case kPaletePosition: + if (stream.readUint16()) + readPaletteInfo(stream); + offset += 16; + break; + default: + offset++; + stream.readByte(); + debug("Field Position %d, Finish Position %d", offset, finishPosition); + break; + } + } +} + +void Frame::readPaletteInfo(Common::SeekableSubReadStreamEndian &stream) { + _palette->firstColor = stream.readByte(); + _palette->lastColor = stream.readByte(); + _palette->flags = stream.readByte(); + _palette->speed = stream.readByte(); + _palette->frameCount = stream.readUint16(); + stream.skip(8); //unknown +} + +void Frame::readSprite(Common::SeekableSubReadStreamEndian &stream, uint16 offset, uint16 size) { + uint16 spritePosition = (offset - 32) / 16; + uint16 spriteStart = spritePosition * 16 + 32; + + uint16 fieldPosition = offset - spriteStart; + uint16 finishPosition = fieldPosition + size; + + Sprite &sprite = *_sprites[spritePosition]; + + while (fieldPosition < finishPosition) { + switch (fieldPosition) { + case kSpritePositionUnk1: + /*byte x1 = */ stream.readByte(); + fieldPosition++; + break; + case kSpritePositionEnabled: + sprite._enabled = (stream.readByte() != 0); + fieldPosition++; + break; + case kSpritePositionUnk2: + /*byte x2 = */ stream.readUint16(); + fieldPosition += 2; + break; + case kSpritePositionFlags: + sprite._flags = stream.readUint16(); + sprite._ink = static_cast<InkType>(sprite._flags & 0x3f); + + if (sprite._flags & 0x40) + sprite._trails = 1; + else + sprite._trails = 0; + + fieldPosition += 2; + break; + case kSpritePositionCastId: + sprite._castId = stream.readUint16(); + fieldPosition += 2; + break; + case kSpritePositionY: + sprite._startPoint.y = stream.readUint16(); + fieldPosition += 2; + break; + case kSpritePositionX: + sprite._startPoint.x = stream.readUint16(); + fieldPosition += 2; + break; + case kSpritePositionWidth: + sprite._width = stream.readUint16(); + fieldPosition += 2; + break; + case kSpritePositionHeight: + sprite._height = stream.readUint16(); + fieldPosition += 2; + break; + default: + //end cycle, go to next sprite channel + readSprite(stream, spriteStart + 16, finishPosition - fieldPosition); + fieldPosition = finishPosition; + break; + } + } +} + +void Frame::prepareFrame(Score *score) { + renderSprites(*score->_surface, false); + renderSprites(*score->_trailSurface, true); + + if (_transType != 0) + //TODO Handle changing area case + playTransition(score); + + if (_sound1 != 0 || _sound2 != 0) { + playSoundChannel(); + } + + g_system->copyRectToScreen(score->_surface->getPixels(), score->_surface->pitch, 0, 0, score->_surface->getBounds().width(), score->_surface->getBounds().height()); +} + +void Frame::playSoundChannel() { + debug(0, "Sound2 %d", _sound2); + debug(0, "Sound1 %d", _sound1); +} + +void Frame::playTransition(Score *score) { + uint16 duration = _transDuration * 250; // _transDuration in 1/4 of sec + duration = (duration == 0 ? 250 : duration); // director support transition duration = 0, but animation play like value = 1, idk. + + if (_transChunkSize == 0) + _transChunkSize = 1; //equal 1 step + + uint16 stepDuration = duration / _transChunkSize; + uint16 steps = duration / stepDuration; + + switch (_transType) { + case kTransCoverDown: + { + uint16 stepSize = score->_movieRect.height() / steps; + Common::Rect r = score->_movieRect; + + for (uint16 i = 1; i < steps; i++) { + r.setHeight(stepSize * i); + + g_system->delayMillis(stepDuration); + score->processEvents(); + + g_system->copyRectToScreen(score->_surface->getPixels(), score->_surface->pitch, 0, 0, r.width(), r.height()); + g_system->updateScreen(); + } + } + break; + case kTransCoverUp: + { + uint16 stepSize = score->_movieRect.height() / steps; + Common::Rect r = score->_movieRect; + + for (uint16 i = 1; i < steps; i++) { + r.setHeight(stepSize * i); + + g_system->delayMillis(stepDuration); + score->processEvents(); + + g_system->copyRectToScreen(score->_surface->getPixels(), score->_surface->pitch, 0, score->_movieRect.height() - stepSize * i, r.width(), r.height()); + g_system->updateScreen(); + } + } + break; + case kTransCoverRight: { + uint16 stepSize = score->_movieRect.width() / steps; + Common::Rect r = score->_movieRect; + + for (uint16 i = 1; i < steps; i++) { + r.setWidth(stepSize * i); + + g_system->delayMillis(stepDuration); + score->processEvents(); + + g_system->copyRectToScreen(score->_surface->getPixels(), score->_surface->pitch, 0, 0, r.width(), r.height()); + g_system->updateScreen(); + } + } + break; + case kTransCoverLeft: { + uint16 stepSize = score->_movieRect.width() / steps; + Common::Rect r = score->_movieRect; + + for (uint16 i = 1; i < steps; i++) { + r.setWidth(stepSize * i); + + g_system->delayMillis(stepDuration); + score->processEvents(); + + g_system->copyRectToScreen(score->_surface->getPixels(), score->_surface->pitch, score->_movieRect.width() - stepSize * i, 0, r.width(), r.height()); + g_system->updateScreen(); + } + } + break; + case kTransCoverUpLeft: { + uint16 stepSize = score->_movieRect.width() / steps; + Common::Rect r = score->_movieRect; + + for (uint16 i = 1; i < steps; i++) { + r.setWidth(stepSize * i); + r.setHeight(stepSize * i); + + g_system->delayMillis(stepDuration); + score->processEvents(); + + g_system->copyRectToScreen(score->_surface->getPixels(), score->_surface->pitch, score->_movieRect.width() - stepSize * i, score->_movieRect.height() - stepSize * i, r.width(), r.height()); + g_system->updateScreen(); + } + } + break; + case kTransCoverUpRight: { + uint16 stepSize = score->_movieRect.width() / steps; + Common::Rect r = score->_movieRect; + + for (uint16 i = 1; i < steps; i++) { + r.setWidth(stepSize * i); + r.setHeight(stepSize * i); + + g_system->delayMillis(stepDuration); + score->processEvents(); + + g_system->copyRectToScreen(score->_surface->getPixels(), score->_surface->pitch, 0, score->_movieRect.height() - stepSize * i, r.width(), r.height()); + g_system->updateScreen(); + } + } + break; + case kTransCoverDownLeft: { + uint16 stepSize = score->_movieRect.width() / steps; + Common::Rect r = score->_movieRect; + + for (uint16 i = 1; i < steps; i++) { + r.setWidth(stepSize * i); + r.setHeight(stepSize * i); + + g_system->delayMillis(stepDuration); + score->processEvents(); + + g_system->copyRectToScreen(score->_surface->getPixels(), score->_surface->pitch, score->_movieRect.width() - stepSize * i, 0, r.width(), r.height()); + g_system->updateScreen(); + } + } + break; + case kTransCoverDownRight: { + uint16 stepSize = score->_movieRect.width() / steps; + Common::Rect r = score->_movieRect; + + for (uint16 i = 1; i < steps; i++) { + r.setWidth(stepSize * i); + r.setHeight(stepSize * i); + + g_system->delayMillis(stepDuration); + score->processEvents(); + + g_system->copyRectToScreen(score->_surface->getPixels(), score->_surface->pitch, 0, 0, r.width(), r.height()); + g_system->updateScreen(); + } + } + break; + default: + warning("Unhandled transition type %d %d %d", _transType, duration, _transChunkSize); + break; + + } +} + +void Frame::renderSprites(Graphics::ManagedSurface &surface, bool renderTrail) { + for (uint16 i = 0; i < CHANNEL_COUNT; i++) { + if (_sprites[i]->_enabled) { + if ((_sprites[i]->_trails == 0 && renderTrail) || (_sprites[i]->_trails == 1 && !renderTrail)) + continue; + + Cast *cast; + if (!_vm->_currentScore->_casts.contains(_sprites[i]->_castId)) { + if (!_vm->getSharedCasts()->contains(_sprites[i]->_castId)) { + warning("Cast id %d not found", _sprites[i]->_castId); + continue; + } else { + cast = _vm->getSharedCasts()->getVal(_sprites[i]->_castId); + } + } else { + cast = _vm->_currentScore->_casts[_sprites[i]->_castId]; + } + + if (cast->type == kCastText) { + renderText(surface, i); + continue; + } + + Image::ImageDecoder *img = getImageFrom(_sprites[i]->_castId, _sprites[i]->_width, _sprites[i]->_height); + + if (!img) { + warning("Image with id %d not found", _sprites[i]->_castId); + continue; + } + + if (!img->getSurface()) { + //TODO + //BMPDecoder doesnt cover all BITD resources (not all have first two bytes 'BM') + //Some BITD's first two bytes 0x6 0x0 + warning("Can not load image %d", _sprites[i]->_castId); + continue; + } + + uint32 regX = static_cast<BitmapCast *>(_sprites[i]->_cast)->regX; + uint32 regY = static_cast<BitmapCast *>(_sprites[i]->_cast)->regY; + uint32 rectLeft = static_cast<BitmapCast *>(_sprites[i]->_cast)->initialRect.left; + uint32 rectTop = static_cast<BitmapCast *>(_sprites[i]->_cast)->initialRect.top; + + int x = _sprites[i]->_startPoint.x - regX + rectLeft; + int y = _sprites[i]->_startPoint.y - regY + rectTop; + int height = _sprites[i]->_height; + int width = _sprites[i]->_width; + + Common::Rect drawRect = Common::Rect(x, y, x + width, y + height); + _drawRects.push_back(drawRect); + + switch (_sprites[i]->_ink) { + case kInkTypeCopy: + surface.blitFrom(*img->getSurface(), Common::Point(x, y)); + break; + case kInkTypeBackgndTrans: + drawBackgndTransSprite(surface, *img->getSurface(), drawRect); + break; + case kInkTypeMatte: + drawMatteSprite(surface, *img->getSurface(), drawRect); + break; + case kInkTypeGhost: + drawGhostSprite(surface, *img->getSurface(), drawRect); + break; + case kInkTypeReverse: + drawReverseSprite(surface, *img->getSurface(), drawRect); + break; + default: + warning("Unhandled ink type %d", _sprites[i]->_ink); + surface.blitFrom(*img->getSurface(), Common::Point(x, y)); + break; + } + } + } +} + +void Frame::renderButton(Graphics::ManagedSurface &surface, uint16 spriteId) { + renderText(surface, spriteId); + + uint16 castID = _sprites[spriteId]->_castId; + ButtonCast *button = static_cast<ButtonCast *>(_vm->_currentScore->_casts[castID]); + + uint32 rectLeft = button->initialRect.left; + uint32 rectTop = button->initialRect.top; + + int x = _sprites[spriteId]->_startPoint.x + rectLeft; + int y = _sprites[spriteId]->_startPoint.y + rectTop; + int height = _sprites[spriteId]->_height; + int width = _sprites[spriteId]->_width; + + switch (button->buttonType) { + case kTypeCheckBox: + //Magic numbers: checkbox square need to move left about 5px from text and 12px side size (d4) + surface.frameRect(Common::Rect(x - 17, y, x + 12, y + 12), 0); + break; + case kTypeButton: + surface.frameRect(Common::Rect(x, y, x + width, y + height), 0); + break; + case kTypeRadio: + warning("STUB: renderButton: kTypeRadio"); + break; + } +} + +Image::ImageDecoder *Frame::getImageFrom(uint16 spriteId, int w, int h) { + uint16 imgId = spriteId + 1024; + Image::ImageDecoder *img = NULL; + + if (_vm->_currentScore->getArchive()->hasResource(MKTAG('D', 'I', 'B', ' '), imgId)) { + img = new DIBDecoder(); + img->loadStream(*_vm->_currentScore->getArchive()->getResource(MKTAG('D', 'I', 'B', ' '), imgId)); + return img; + } + + if (_vm->getSharedDIB() != NULL && _vm->getSharedDIB()->contains(imgId)) { + img = new DIBDecoder(); + img->loadStream(*_vm->getSharedDIB()->getVal(imgId)); + return img; + } + + if (_vm->_currentScore->getArchive()->hasResource(MKTAG('B', 'I', 'T', 'D'), imgId)) { + if (_vm->getVersion() < 4) { + img = new BITDDecoder(w, h); + } else { + img = new Image::BitmapDecoder(); + } + + if (debugChannelSet(8, kDebugLoading)) { + Common::SeekableReadStream *s = _vm->_currentScore->getArchive()->getResource(MKTAG('B', 'I', 'T', 'D'), imgId); + byte buf[1024]; + int n = s->read(buf, 1024); + Common::hexdump(buf, n); + } + + img->loadStream(*_vm->_currentScore->getArchive()->getResource(MKTAG('B', 'I', 'T', 'D'), imgId)); + return img; + } + + if (_vm->getSharedBMP() != NULL && _vm->getSharedBMP()->contains(imgId)) { + img = new Image::BitmapDecoder(); + img->loadStream(*_vm->getSharedBMP()->getVal(imgId)); + return img; + } + + warning("Image %d not found", spriteId); + return img; +} + + +void Frame::renderText(Graphics::ManagedSurface &surface, uint16 spriteID) { + uint16 castID = _sprites[spriteID]->_castId; + + TextCast *textCast = static_cast<TextCast *>(_vm->_currentScore->_casts[castID]); + Common::SeekableSubReadStreamEndian *textStream; + + if (_vm->_currentScore->_movieArchive->hasResource(MKTAG('S','T','X','T'), castID + 1024)) { + textStream = _vm->_currentScore->_movieArchive->getResource(MKTAG('S','T','X','T'), castID + 1024); + } else { + textStream = _vm->getSharedSTXT()->getVal(spriteID + 1024); + } + /*uint32 unk1 = */ textStream->readUint32(); + uint32 strLen = textStream->readUint32(); + /*uin32 dataLen = */ textStream->readUint32(); + Common::String text; + + for (uint32 i = 0; i < strLen; i++) { + byte ch = textStream->readByte(); + if (ch == 0x0d) { + ch = '\n'; + } + text += ch; + } + + uint32 rectLeft = static_cast<TextCast *>(_sprites[spriteID]->_cast)->initialRect.left; + uint32 rectTop = static_cast<TextCast *>(_sprites[spriteID]->_cast)->initialRect.top; + + int x = _sprites[spriteID]->_startPoint.x + rectLeft; + int y = _sprites[spriteID]->_startPoint.y + rectTop; + int height = _sprites[spriteID]->_height; + int width = _sprites[spriteID]->_width; + + const char *fontName; + + if (_vm->_currentScore->_fontMap.contains(textCast->fontId)) { + fontName = _vm->_currentScore->_fontMap[textCast->fontId].c_str(); + } else if ((fontName = _vm->_wm->getFontName(textCast->fontId, textCast->fontSize)) == NULL) { + warning("Unknown font id %d, falling back to default", textCast->fontId); + fontName = _vm->_wm->getFontName(0, 12); + } + + const Graphics::Font *font = _vm->_wm->getFont(fontName, Graphics::FontManager::kBigGUIFont); + + font->drawString(&surface, text, x, y, width, 0); + + if (textCast->borderSize != kSizeNone) { + uint16 size = textCast->borderSize; + + //Indent from borders, measured in d4 + x -= 1; + y -= 4; + + height += 4; + width += 1; + + while (size) { + surface.frameRect(Common::Rect(x, y, x + height, y + width), 0); + x--; + y--; + height += 2; + width += 2; + size--; + } + } + + if (textCast->gutterSize != kSizeNone) { + x -= 1; + y -= 4; + + height += 4; + width += 1; + uint16 size = textCast->gutterSize; + + surface.frameRect(Common::Rect(x, y, x + height, y + width), 0); + + while (size) { + surface.drawLine(x + width, y, x + width, y + height, 0); + surface.drawLine(x, y + height, x + width, y + height, 0); + x++; + y++; + size--; + } + } +} + +void Frame::drawBackgndTransSprite(Graphics::ManagedSurface &target, const Graphics::Surface &sprite, Common::Rect &drawRect) { + uint8 skipColor = _vm->getPaletteColorCount() - 1; //FIXME is it always white (last entry in pallette) ? + + for (int ii = 0; ii < sprite.h; ii++) { + const byte *src = (const byte *)sprite.getBasePtr(0, ii); + byte *dst = (byte *)target.getBasePtr(drawRect.left, drawRect.top + ii); + + for (int j = 0; j < drawRect.width(); j++) { + if (*src != skipColor) + *dst = *src; + + src++; + dst++; + } + } +} + +void Frame::drawGhostSprite(Graphics::ManagedSurface &target, const Graphics::Surface &sprite, Common::Rect &drawRect) { + uint8 skipColor = _vm->getPaletteColorCount() - 1; + for (int ii = 0; ii < sprite.h; ii++) { + const byte *src = (const byte *)sprite.getBasePtr(0, ii); + byte *dst = (byte *)target.getBasePtr(drawRect.left, drawRect.top + ii); + + for (int j = 0; j < drawRect.width(); j++) { + if ((getSpriteIDFromPos(Common::Point(drawRect.left + j, drawRect.top + ii)) != 0) && (*src != skipColor)) + *dst = (_vm->getPaletteColorCount() - 1) - *src; //Oposite color + + src++; + dst++; + } + } +} + +void Frame::drawReverseSprite(Graphics::ManagedSurface &target, const Graphics::Surface &sprite, Common::Rect &drawRect) { + uint8 skipColor = _vm->getPaletteColorCount() - 1; + for (int ii = 0; ii < sprite.h; ii++) { + const byte *src = (const byte *)sprite.getBasePtr(0, ii); + byte *dst = (byte *)target.getBasePtr(drawRect.left, drawRect.top + ii); + + for (int j = 0; j < drawRect.width(); j++) { + if ((getSpriteIDFromPos(Common::Point(drawRect.left + j, drawRect.top + ii)) != 0)) + *dst = (_vm->getPaletteColorCount() - 1) - *src; + else if (*src != skipColor) + *dst = *src; + src++; + dst++; + } + } +} + +void Frame::drawMatteSprite(Graphics::ManagedSurface &target, const Graphics::Surface &sprite, Common::Rect &drawRect) { + //Like background trans, but all white pixels NOT ENCLOSED by coloured pixels are transparent + Graphics::Surface tmp; + tmp.copyFrom(sprite); + + // Searching white color in the corners + int whiteColor = -1; + + for (int corner = 0; corner < 4; corner++) { + int x = (corner & 0x1) ? tmp.w - 1 : 0; + int y = (corner & 0x2) ? tmp.h - 1 : 0; + + byte color = *(byte *)tmp.getBasePtr(x, y); + + if (_vm->getPalette()[color * 3 + 0] == 0xff && + _vm->getPalette()[color * 3 + 1] == 0xff && + _vm->getPalette()[color * 3 + 2] == 0xff) { + whiteColor = color; + break; + } + } + + if (whiteColor == -1) { + warning("No white color for Matte image"); + whiteColor = *(byte *)tmp.getBasePtr(0, 0); + } + + Graphics::FloodFill ff(&tmp, whiteColor, 0, true); + + for (int yy = 0; yy < tmp.h; yy++) { + ff.addSeed(0, yy); + ff.addSeed(tmp.w - 1, yy); + } + + for (int xx = 0; xx < tmp.w; xx++) { + ff.addSeed(xx, 0); + ff.addSeed(xx, tmp.h - 1); + } + ff.fillMask(); + + for (int yy = 0; yy < tmp.h; yy++) { + const byte *src = (const byte *)tmp.getBasePtr(0, yy); + const byte *mask = (const byte *)ff.getMask()->getBasePtr(0, yy); + byte *dst = (byte *)target.getBasePtr(drawRect.left, drawRect.top + yy); + + for (int xx = 0; xx < drawRect.width(); xx++, src++, dst++, mask++) + if (*mask == 0) + *dst = *src; + } + + tmp.free(); +} + +uint16 Frame::getSpriteIDFromPos(Common::Point pos) { + //Find first from top to bottom + for (uint16 i = _drawRects.size() - 1; i > 0; i--) { + if (_drawRects[i].contains(pos)) + return i; + } + + return 0; +} + +} //End of namespace Director diff --git a/engines/director/frame.h b/engines/director/frame.h new file mode 100644 index 0000000000..f9cef676cd --- /dev/null +++ b/engines/director/frame.h @@ -0,0 +1,146 @@ +/* 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. + * + */ + +#ifndef DIRECTOR_FRAME_H +#define DIRECTOR_FRAME_H + +#include "graphics/managed_surface.h" +#include "image/image_decoder.h" + +namespace Director { + +class Sprite; + +#define CHANNEL_COUNT 24 + +enum TransitionType { + kTransNone, + kTransWipeRight, + kTransWipeLeft, + kTransWipeDown, + kTransWipeUp, + kTransCenterOutHorizontal, + kTransEdgesInHorizontal, + kTransCenterOutVertical, + kTransEdgesInVertical, + kTransCenterOutSquare, + kTransEdgesInSquare, + kTransPushLeft, + kTransPushRight, + kTransPushDown, + kTransPushUp, + kTransRevealUp, + kTransRevealUpRight, + kTransRevealRight, + kTransRevealDown, + kTransRevealDownRight, + kTransRevealDownLeft, + kTransRevealLeft, + kTransRevealUpLeft, + kTransDissolvePixelsFast, + kTransDissolveBoxyRects, + kTransDissolveBoxySquares, + kTransDissolvePatterns, + kTransRandomRows, + kTransRandomColumns, + kTransCoverDown, + kTransCoverDownLeft, + kTransCoverDownRight, + kTransCoverLeft, + kTransCoverRight, + kTransCoverUp, + kTransCoverUpLeft, + kTransCoverUpRight, + kTransTypeVenitianBlind, + kTransTypeCheckerboard, + kTransTypeStripsBottomBuildLeft, + kTransTypeStripsBottomBuildRight, + kTransTypeStripsLeftBuildDown, + kTransTypeStripsLeftBuildUp, + kTransTypeStripsRightBuildDown, + kTransTypeStripsRightBuildUp, + kTransTypeStripsTopBuildLeft, + kTransTypeStripsTopBuildRight, + kTransZoomOpen, + kTransZoomClose, + kTransVerticalBinds, + kTransDissolveBitsTrans, + kTransDissolvePixels, + kTransDissolveBits +}; + +struct PaletteInfo { + uint8 firstColor; + uint8 lastColor; + uint8 flags; + uint8 speed; + uint16 frameCount; +}; + + +class Frame { +public: + Frame(DirectorEngine *vm); + Frame(const Frame &frame); + ~Frame(); + void readChannel(Common::SeekableSubReadStreamEndian &stream, uint16 offset, uint16 size); + void prepareFrame(Score *score); + uint16 getSpriteIDFromPos(Common::Point pos); + +private: + void playTransition(Score *score); + void playSoundChannel(); + void renderSprites(Graphics::ManagedSurface &surface, bool renderTrail); + void renderText(Graphics::ManagedSurface &surface, uint16 spriteId); + void renderButton(Graphics::ManagedSurface &surface, uint16 spriteId); + void readPaletteInfo(Common::SeekableSubReadStreamEndian &stream); + void readSprite(Common::SeekableSubReadStreamEndian &stream, uint16 offset, uint16 size); + void readMainChannels(Common::SeekableSubReadStreamEndian &stream, uint16 offset, uint16 size); + Image::ImageDecoder *getImageFrom(uint16 spriteID, int w, int h); + void drawBackgndTransSprite(Graphics::ManagedSurface &target, const Graphics::Surface &sprite, Common::Rect &drawRect); + void drawMatteSprite(Graphics::ManagedSurface &target, const Graphics::Surface &sprite, Common::Rect &drawRect); + void drawGhostSprite(Graphics::ManagedSurface &target, const Graphics::Surface &sprite, Common::Rect &drawRect); + void drawReverseSprite(Graphics::ManagedSurface &target, const Graphics::Surface &sprite, Common::Rect &drawRect); +public: + uint8 _actionId; + uint8 _transDuration; + uint8 _transArea; //1 - Whole Stage, 0 - Changing Area + uint8 _transChunkSize; + TransitionType _transType; + PaletteInfo *_palette; + uint8 _tempo; + + uint16 _sound1; + uint8 _soundType1; + uint16 _sound2; + uint8 _soundType2; + + uint8 _skipFrameFlag; + uint8 _blend; + Common::Array<Sprite *> _sprites; + Common::Array<Common::Rect > _drawRects; + DirectorEngine *_vm; +}; + +} //End of namespace Director + +#endif diff --git a/engines/director/lingo/lingo-the.cpp b/engines/director/lingo/lingo-the.cpp index d868b8ab00..879ff4854d 100644 --- a/engines/director/lingo/lingo-the.cpp +++ b/engines/director/lingo/lingo-the.cpp @@ -21,6 +21,7 @@ */ #include "engines/director/lingo/lingo.h" +#include "director/sprite.h" namespace Director { diff --git a/engines/director/module.mk b/engines/director/module.mk index 05e92b76e0..c37e9d9b9b 100644 --- a/engines/director/module.mk +++ b/engines/director/module.mk @@ -3,11 +3,13 @@ MODULE := engines/director MODULE_OBJS = \ detection.o \ director.o \ + frame.o \ images.o \ movie.o \ resource.o \ score.o \ sound.o \ + sprite.o \ lingo/lingo-gr.o \ lingo/lingo.o \ lingo/lingo-builtins.o \ diff --git a/engines/director/score.cpp b/engines/director/score.cpp index ccadac212c..2812f29919 100644 --- a/engines/director/score.cpp +++ b/engines/director/score.cpp @@ -32,11 +32,12 @@ #include "engines/util.h" #include "graphics/managed_surface.h" #include "graphics/macgui/macwindowmanager.h" -#include "image/bmp.h" #include "graphics/fontman.h" #include "graphics/fonts/bdf.h" #include "director/score.h" +#include "director/frame.h" +#include "director/sprite.h" #include "director/images.h" #include "director/resource.h" #include "director/lingo/lingo.h" @@ -839,785 +840,4 @@ Sprite *Score::getSpriteById(uint16 id) { } } -Frame::Frame(DirectorEngine *vm) { - _vm = vm; - _transDuration = 0; - _transType = kTransNone; - _transArea = 0; - _transChunkSize = 0; - _tempo = 0; - - _sound1 = 0; - _sound2 = 0; - _soundType1 = 0; - _soundType2 = 0; - - _actionId = 0; - _skipFrameFlag = 0; - _blend = 0; - - _sprites.resize(CHANNEL_COUNT); - - for (uint16 i = 0; i < _sprites.size(); i++) { - Sprite *sp = new Sprite(); - _sprites[i] = sp; - } -} - -Frame::Frame(const Frame &frame) { - _vm = frame._vm; - _actionId = frame._actionId; - _transArea = frame._transArea; - _transDuration = frame._transDuration; - _transType = frame._transType; - _transChunkSize = frame._transChunkSize; - _tempo = frame._tempo; - _sound1 = frame._sound1; - _sound2 = frame._sound2; - _soundType1 = frame._soundType1; - _soundType2 = frame._soundType2; - _skipFrameFlag = frame._skipFrameFlag; - _blend = frame._blend; - _palette = new PaletteInfo(); - - _sprites.resize(CHANNEL_COUNT); - - for (uint16 i = 0; i < CHANNEL_COUNT; i++) { - _sprites[i] = new Sprite(*frame._sprites[i]); - } -} - -Frame::~Frame() { - delete _palette; -} - -void Frame::readChannel(Common::SeekableSubReadStreamEndian &stream, uint16 offset, uint16 size) { - if (offset >= 32) { - if (size <= 16) - readSprite(stream, offset, size); - else { - //read > 1 sprites channel - while (size > 16) { - byte spritePosition = (offset - 32) / 16; - uint16 nextStart = (spritePosition + 1) * 16 + 32; - uint16 needSize = nextStart - offset; - readSprite(stream, offset, needSize); - offset += needSize; - size -= needSize; - } - readSprite(stream, offset, size); - } - } else { - readMainChannels(stream, offset, size); - } -} - -void Frame::readMainChannels(Common::SeekableSubReadStreamEndian &stream, uint16 offset, uint16 size) { - uint16 finishPosition = offset + size; - - while (offset < finishPosition) { - switch(offset) { - case kScriptIdPosition: - _actionId = stream.readByte(); - offset++; - break; - case kSoundType1Position: - _soundType1 = stream.readByte(); - offset++; - break; - case kTransFlagsPosition: { - uint8 transFlags = stream.readByte(); - if (transFlags & 0x80) - _transArea = 1; - else - _transArea = 0; - _transDuration = transFlags & 0x7f; - offset++; - } - break; - case kTransChunkSizePosition: - _transChunkSize = stream.readByte(); - offset++; - break; - case kTempoPosition: - _tempo = stream.readByte(); - offset++; - break; - case kTransTypePosition: - _transType = static_cast<TransitionType>(stream.readByte()); - offset++; - break; - case kSound1Position: - _sound1 = stream.readUint16(); - offset+=2; - break; - case kSkipFrameFlagsPosition: - _skipFrameFlag = stream.readByte(); - offset++; - break; - case kBlendPosition: - _blend = stream.readByte(); - offset++; - break; - case kSound2Position: - _sound2 = stream.readUint16(); - offset += 2; - break; - case kSound2TypePosition: - _soundType2 = stream.readByte(); - offset += 1; - break; - case kPaletePosition: - if (stream.readUint16()) - readPaletteInfo(stream); - offset += 16; - break; - default: - offset++; - stream.readByte(); - debug("Field Position %d, Finish Position %d", offset, finishPosition); - break; - } - } -} - -void Frame::readPaletteInfo(Common::SeekableSubReadStreamEndian &stream) { - _palette->firstColor = stream.readByte(); - _palette->lastColor = stream.readByte(); - _palette->flags = stream.readByte(); - _palette->speed = stream.readByte(); - _palette->frameCount = stream.readUint16(); - stream.skip(8); //unknown -} - -void Frame::readSprite(Common::SeekableSubReadStreamEndian &stream, uint16 offset, uint16 size) { - uint16 spritePosition = (offset - 32) / 16; - uint16 spriteStart = spritePosition * 16 + 32; - - uint16 fieldPosition = offset - spriteStart; - uint16 finishPosition = fieldPosition + size; - - Sprite &sprite = *_sprites[spritePosition]; - - while (fieldPosition < finishPosition) { - switch (fieldPosition) { - case kSpritePositionUnk1: - /*byte x1 = */ stream.readByte(); - fieldPosition++; - break; - case kSpritePositionEnabled: - sprite._enabled = (stream.readByte() != 0); - fieldPosition++; - break; - case kSpritePositionUnk2: - /*byte x2 = */ stream.readUint16(); - fieldPosition += 2; - break; - case kSpritePositionFlags: - sprite._flags = stream.readUint16(); - sprite._ink = static_cast<InkType>(sprite._flags & 0x3f); - - if (sprite._flags & 0x40) - sprite._trails = 1; - else - sprite._trails = 0; - - fieldPosition += 2; - break; - case kSpritePositionCastId: - sprite._castId = stream.readUint16(); - fieldPosition += 2; - break; - case kSpritePositionY: - sprite._startPoint.y = stream.readUint16(); - fieldPosition += 2; - break; - case kSpritePositionX: - sprite._startPoint.x = stream.readUint16(); - fieldPosition += 2; - break; - case kSpritePositionWidth: - sprite._width = stream.readUint16(); - fieldPosition += 2; - break; - case kSpritePositionHeight: - sprite._height = stream.readUint16(); - fieldPosition += 2; - break; - default: - //end cycle, go to next sprite channel - readSprite(stream, spriteStart + 16, finishPosition - fieldPosition); - fieldPosition = finishPosition; - break; - } - } -} - -void Frame::prepareFrame(Score *score) { - renderSprites(*score->_surface, false); - renderSprites(*score->_trailSurface, true); - - if (_transType != 0) - //TODO Handle changing area case - playTransition(score); - - if (_sound1 != 0 || _sound2 != 0) { - playSoundChannel(); - } - - g_system->copyRectToScreen(score->_surface->getPixels(), score->_surface->pitch, 0, 0, score->_surface->getBounds().width(), score->_surface->getBounds().height()); -} - -void Frame::playSoundChannel() { - debug(0, "Sound2 %d", _sound2); - debug(0, "Sound1 %d", _sound1); -} - -void Frame::playTransition(Score *score) { - uint16 duration = _transDuration * 250; // _transDuration in 1/4 of sec - duration = (duration == 0 ? 250 : duration); // director support transition duration = 0, but animation play like value = 1, idk. - - if (_transChunkSize == 0) - _transChunkSize = 1; //equal 1 step - - uint16 stepDuration = duration / _transChunkSize; - uint16 steps = duration / stepDuration; - - switch (_transType) { - case kTransCoverDown: - { - uint16 stepSize = score->_movieRect.height() / steps; - Common::Rect r = score->_movieRect; - - for (uint16 i = 1; i < steps; i++) { - r.setHeight(stepSize * i); - - g_system->delayMillis(stepDuration); - score->processEvents(); - - g_system->copyRectToScreen(score->_surface->getPixels(), score->_surface->pitch, 0, 0, r.width(), r.height()); - g_system->updateScreen(); - } - } - break; - case kTransCoverUp: - { - uint16 stepSize = score->_movieRect.height() / steps; - Common::Rect r = score->_movieRect; - - for (uint16 i = 1; i < steps; i++) { - r.setHeight(stepSize * i); - - g_system->delayMillis(stepDuration); - score->processEvents(); - - g_system->copyRectToScreen(score->_surface->getPixels(), score->_surface->pitch, 0, score->_movieRect.height() - stepSize * i, r.width(), r.height()); - g_system->updateScreen(); - } - } - break; - case kTransCoverRight: { - uint16 stepSize = score->_movieRect.width() / steps; - Common::Rect r = score->_movieRect; - - for (uint16 i = 1; i < steps; i++) { - r.setWidth(stepSize * i); - - g_system->delayMillis(stepDuration); - score->processEvents(); - - g_system->copyRectToScreen(score->_surface->getPixels(), score->_surface->pitch, 0, 0, r.width(), r.height()); - g_system->updateScreen(); - } - } - break; - case kTransCoverLeft: { - uint16 stepSize = score->_movieRect.width() / steps; - Common::Rect r = score->_movieRect; - - for (uint16 i = 1; i < steps; i++) { - r.setWidth(stepSize * i); - - g_system->delayMillis(stepDuration); - score->processEvents(); - - g_system->copyRectToScreen(score->_surface->getPixels(), score->_surface->pitch, score->_movieRect.width() - stepSize * i, 0, r.width(), r.height()); - g_system->updateScreen(); - } - } - break; - case kTransCoverUpLeft: { - uint16 stepSize = score->_movieRect.width() / steps; - Common::Rect r = score->_movieRect; - - for (uint16 i = 1; i < steps; i++) { - r.setWidth(stepSize * i); - r.setHeight(stepSize * i); - - g_system->delayMillis(stepDuration); - score->processEvents(); - - g_system->copyRectToScreen(score->_surface->getPixels(), score->_surface->pitch, score->_movieRect.width() - stepSize * i, score->_movieRect.height() - stepSize * i, r.width(), r.height()); - g_system->updateScreen(); - } - } - break; - case kTransCoverUpRight: { - uint16 stepSize = score->_movieRect.width() / steps; - Common::Rect r = score->_movieRect; - - for (uint16 i = 1; i < steps; i++) { - r.setWidth(stepSize * i); - r.setHeight(stepSize * i); - - g_system->delayMillis(stepDuration); - score->processEvents(); - - g_system->copyRectToScreen(score->_surface->getPixels(), score->_surface->pitch, 0, score->_movieRect.height() - stepSize * i, r.width(), r.height()); - g_system->updateScreen(); - } - } - break; - case kTransCoverDownLeft: { - uint16 stepSize = score->_movieRect.width() / steps; - Common::Rect r = score->_movieRect; - - for (uint16 i = 1; i < steps; i++) { - r.setWidth(stepSize * i); - r.setHeight(stepSize * i); - - g_system->delayMillis(stepDuration); - score->processEvents(); - - g_system->copyRectToScreen(score->_surface->getPixels(), score->_surface->pitch, score->_movieRect.width() - stepSize * i, 0, r.width(), r.height()); - g_system->updateScreen(); - } - } - break; - case kTransCoverDownRight: { - uint16 stepSize = score->_movieRect.width() / steps; - Common::Rect r = score->_movieRect; - - for (uint16 i = 1; i < steps; i++) { - r.setWidth(stepSize * i); - r.setHeight(stepSize * i); - - g_system->delayMillis(stepDuration); - score->processEvents(); - - g_system->copyRectToScreen(score->_surface->getPixels(), score->_surface->pitch, 0, 0, r.width(), r.height()); - g_system->updateScreen(); - } - } - break; - default: - warning("Unhandled transition type %d %d %d", _transType, duration, _transChunkSize); - break; - - } -} - -void Frame::renderSprites(Graphics::ManagedSurface &surface, bool renderTrail) { - for (uint16 i = 0; i < CHANNEL_COUNT; i++) { - if (_sprites[i]->_enabled) { - if ((_sprites[i]->_trails == 0 && renderTrail) || (_sprites[i]->_trails == 1 && !renderTrail)) - continue; - - Cast *cast; - if (!_vm->_currentScore->_casts.contains(_sprites[i]->_castId)) { - if (!_vm->getSharedCasts()->contains(_sprites[i]->_castId)) { - warning("Cast id %d not found", _sprites[i]->_castId); - continue; - } else { - cast = _vm->getSharedCasts()->getVal(_sprites[i]->_castId); - } - } else { - cast = _vm->_currentScore->_casts[_sprites[i]->_castId]; - } - - if (cast->type == kCastText) { - renderText(surface, i); - continue; - } - - Image::ImageDecoder *img = getImageFrom(_sprites[i]->_castId, _sprites[i]->_width, _sprites[i]->_height); - - if (!img) { - warning("Image with id %d not found", _sprites[i]->_castId); - continue; - } - - if (!img->getSurface()) { - //TODO - //BMPDecoder doesnt cover all BITD resources (not all have first two bytes 'BM') - //Some BITD's first two bytes 0x6 0x0 - warning("Can not load image %d", _sprites[i]->_castId); - continue; - } - - uint32 regX = static_cast<BitmapCast *>(_sprites[i]->_cast)->regX; - uint32 regY = static_cast<BitmapCast *>(_sprites[i]->_cast)->regY; - uint32 rectLeft = static_cast<BitmapCast *>(_sprites[i]->_cast)->initialRect.left; - uint32 rectTop = static_cast<BitmapCast *>(_sprites[i]->_cast)->initialRect.top; - - int x = _sprites[i]->_startPoint.x - regX + rectLeft; - int y = _sprites[i]->_startPoint.y - regY + rectTop; - int height = _sprites[i]->_height; - int width = _sprites[i]->_width; - - Common::Rect drawRect = Common::Rect(x, y, x + width, y + height); - _drawRects.push_back(drawRect); - - switch (_sprites[i]->_ink) { - case kInkTypeCopy: - surface.blitFrom(*img->getSurface(), Common::Point(x, y)); - break; - case kInkTypeBackgndTrans: - drawBackgndTransSprite(surface, *img->getSurface(), drawRect); - break; - case kInkTypeMatte: - drawMatteSprite(surface, *img->getSurface(), drawRect); - break; - case kInkTypeGhost: - drawGhostSprite(surface, *img->getSurface(), drawRect); - break; - case kInkTypeReverse: - drawReverseSprite(surface, *img->getSurface(), drawRect); - break; - default: - warning("Unhandled ink type %d", _sprites[i]->_ink); - surface.blitFrom(*img->getSurface(), Common::Point(x, y)); - break; - } - } - } -} - -void Frame::renderButton(Graphics::ManagedSurface &surface, uint16 spriteId) { - renderText(surface, spriteId); - - uint16 castID = _sprites[spriteId]->_castId; - ButtonCast *button = static_cast<ButtonCast *>(_vm->_currentScore->_casts[castID]); - - uint32 rectLeft = button->initialRect.left; - uint32 rectTop = button->initialRect.top; - - int x = _sprites[spriteId]->_startPoint.x + rectLeft; - int y = _sprites[spriteId]->_startPoint.y + rectTop; - int height = _sprites[spriteId]->_height; - int width = _sprites[spriteId]->_width; - - switch (button->buttonType) { - case kTypeCheckBox: - //Magic numbers: checkbox square need to move left about 5px from text and 12px side size (d4) - surface.frameRect(Common::Rect(x - 17, y, x + 12, y + 12), 0); - break; - case kTypeButton: - surface.frameRect(Common::Rect(x, y, x + width, y + height), 0); - break; - case kTypeRadio: - warning("STUB: renderButton: kTypeRadio"); - break; - } -} - -Image::ImageDecoder *Frame::getImageFrom(uint16 spriteId, int w, int h) { - uint16 imgId = spriteId + 1024; - Image::ImageDecoder *img = NULL; - - if (_vm->_currentScore->getArchive()->hasResource(MKTAG('D', 'I', 'B', ' '), imgId)) { - img = new DIBDecoder(); - img->loadStream(*_vm->_currentScore->getArchive()->getResource(MKTAG('D', 'I', 'B', ' '), imgId)); - return img; - } - - if (_vm->getSharedDIB() != NULL && _vm->getSharedDIB()->contains(imgId)) { - img = new DIBDecoder(); - img->loadStream(*_vm->getSharedDIB()->getVal(imgId)); - return img; - } - - if (_vm->_currentScore->getArchive()->hasResource(MKTAG('B', 'I', 'T', 'D'), imgId)) { - if (_vm->getVersion() < 4) { - img = new BITDDecoder(w, h); - } else { - img = new Image::BitmapDecoder(); - } - - if (debugChannelSet(8, kDebugLoading)) { - Common::SeekableReadStream *s = _vm->_currentScore->getArchive()->getResource(MKTAG('B', 'I', 'T', 'D'), imgId); - byte buf[1024]; - int n = s->read(buf, 1024); - Common::hexdump(buf, n); - } - - img->loadStream(*_vm->_currentScore->getArchive()->getResource(MKTAG('B', 'I', 'T', 'D'), imgId)); - return img; - } - - if (_vm->getSharedBMP() != NULL && _vm->getSharedBMP()->contains(imgId)) { - img = new Image::BitmapDecoder(); - img->loadStream(*_vm->getSharedBMP()->getVal(imgId)); - return img; - } - - warning("Image %d not found", spriteId); - return img; -} - - -void Frame::renderText(Graphics::ManagedSurface &surface, uint16 spriteID) { - uint16 castID = _sprites[spriteID]->_castId; - - TextCast *textCast = static_cast<TextCast *>(_vm->_currentScore->_casts[castID]); - Common::SeekableSubReadStreamEndian *textStream; - - if (_vm->_currentScore->_movieArchive->hasResource(MKTAG('S','T','X','T'), castID + 1024)) { - textStream = _vm->_currentScore->_movieArchive->getResource(MKTAG('S','T','X','T'), castID + 1024); - } else { - textStream = _vm->getSharedSTXT()->getVal(spriteID + 1024); - } - /*uint32 unk1 = */ textStream->readUint32(); - uint32 strLen = textStream->readUint32(); - /*uin32 dataLen = */ textStream->readUint32(); - Common::String text; - - for (uint32 i = 0; i < strLen; i++) { - byte ch = textStream->readByte(); - if (ch == 0x0d) { - ch = '\n'; - } - text += ch; - } - - uint32 rectLeft = static_cast<TextCast *>(_sprites[spriteID]->_cast)->initialRect.left; - uint32 rectTop = static_cast<TextCast *>(_sprites[spriteID]->_cast)->initialRect.top; - - int x = _sprites[spriteID]->_startPoint.x + rectLeft; - int y = _sprites[spriteID]->_startPoint.y + rectTop; - int height = _sprites[spriteID]->_height; - int width = _sprites[spriteID]->_width; - - const char *fontName; - - if (_vm->_currentScore->_fontMap.contains(textCast->fontId)) { - fontName = _vm->_currentScore->_fontMap[textCast->fontId].c_str(); - } else if ((fontName = _vm->_wm->getFontName(textCast->fontId, textCast->fontSize)) == NULL) { - warning("Unknown font id %d, falling back to default", textCast->fontId); - fontName = _vm->_wm->getFontName(0, 12); - } - - const Graphics::Font *font = _vm->_wm->getFont(fontName, Graphics::FontManager::kBigGUIFont); - - font->drawString(&surface, text, x, y, width, 0); - - if (textCast->borderSize != kSizeNone) { - uint16 size = textCast->borderSize; - - //Indent from borders, measured in d4 - x -= 1; - y -= 4; - - height += 4; - width += 1; - - while (size) { - surface.frameRect(Common::Rect(x, y, x + height, y + width), 0); - x--; - y--; - height += 2; - width += 2; - size--; - } - } - - if (textCast->gutterSize != kSizeNone) { - x -= 1; - y -= 4; - - height += 4; - width += 1; - uint16 size = textCast->gutterSize; - - surface.frameRect(Common::Rect(x, y, x + height, y + width), 0); - - while (size) { - surface.drawLine(x + width, y, x + width, y + height, 0); - surface.drawLine(x, y + height, x + width, y + height, 0); - x++; - y++; - size--; - } - } -} - -void Frame::drawBackgndTransSprite(Graphics::ManagedSurface &target, const Graphics::Surface &sprite, Common::Rect &drawRect) { - uint8 skipColor = _vm->getPaletteColorCount() - 1; //FIXME is it always white (last entry in pallette) ? - - for (int ii = 0; ii < sprite.h; ii++) { - const byte *src = (const byte *)sprite.getBasePtr(0, ii); - byte *dst = (byte *)target.getBasePtr(drawRect.left, drawRect.top + ii); - - for (int j = 0; j < drawRect.width(); j++) { - if (*src != skipColor) - *dst = *src; - - src++; - dst++; - } - } -} - -void Frame::drawGhostSprite(Graphics::ManagedSurface &target, const Graphics::Surface &sprite, Common::Rect &drawRect) { - uint8 skipColor = _vm->getPaletteColorCount() - 1; - for (int ii = 0; ii < sprite.h; ii++) { - const byte *src = (const byte *)sprite.getBasePtr(0, ii); - byte *dst = (byte *)target.getBasePtr(drawRect.left, drawRect.top + ii); - - for (int j = 0; j < drawRect.width(); j++) { - if ((getSpriteIDFromPos(Common::Point(drawRect.left + j, drawRect.top + ii)) != 0) && (*src != skipColor)) - *dst = (_vm->getPaletteColorCount() - 1) - *src; //Oposite color - - src++; - dst++; - } - } -} - -void Frame::drawReverseSprite(Graphics::ManagedSurface &target, const Graphics::Surface &sprite, Common::Rect &drawRect) { - uint8 skipColor = _vm->getPaletteColorCount() - 1; - for (int ii = 0; ii < sprite.h; ii++) { - const byte *src = (const byte *)sprite.getBasePtr(0, ii); - byte *dst = (byte *)target.getBasePtr(drawRect.left, drawRect.top + ii); - - for (int j = 0; j < drawRect.width(); j++) { - if ((getSpriteIDFromPos(Common::Point(drawRect.left + j, drawRect.top + ii)) != 0)) - *dst = (_vm->getPaletteColorCount() - 1) - *src; - else if (*src != skipColor) - *dst = *src; - src++; - dst++; - } - } -} - -void Frame::drawMatteSprite(Graphics::ManagedSurface &target, const Graphics::Surface &sprite, Common::Rect &drawRect) { - //Like background trans, but all white pixels NOT ENCLOSED by coloured pixels are transparent - Graphics::Surface tmp; - tmp.copyFrom(sprite); - - // Searching white color in the corners - int whiteColor = -1; - - for (int corner = 0; corner < 4; corner++) { - int x = (corner & 0x1) ? tmp.w - 1 : 0; - int y = (corner & 0x2) ? tmp.h - 1 : 0; - - byte color = *(byte *)tmp.getBasePtr(x, y); - - if (_vm->getPalette()[color * 3 + 0] == 0xff && - _vm->getPalette()[color * 3 + 1] == 0xff && - _vm->getPalette()[color * 3 + 2] == 0xff) { - whiteColor = color; - break; - } - } - - if (whiteColor == -1) { - warning("No white color for Matte image"); - whiteColor = *(byte *)tmp.getBasePtr(0, 0); - } - - Graphics::FloodFill ff(&tmp, whiteColor, 0, true); - - for (int yy = 0; yy < tmp.h; yy++) { - ff.addSeed(0, yy); - ff.addSeed(tmp.w - 1, yy); - } - - for (int xx = 0; xx < tmp.w; xx++) { - ff.addSeed(xx, 0); - ff.addSeed(xx, tmp.h - 1); - } - ff.fillMask(); - - for (int yy = 0; yy < tmp.h; yy++) { - const byte *src = (const byte *)tmp.getBasePtr(0, yy); - const byte *mask = (const byte *)ff.getMask()->getBasePtr(0, yy); - byte *dst = (byte *)target.getBasePtr(drawRect.left, drawRect.top + yy); - - for (int xx = 0; xx < drawRect.width(); xx++, src++, dst++, mask++) - if (*mask == 0) - *dst = *src; - } - - tmp.free(); -} - -uint16 Frame::getSpriteIDFromPos(Common::Point pos) { - //Find first from top to bottom - for (uint16 i = _drawRects.size() - 1; i > 0; i--) { - if (_drawRects[i].contains(pos)) - return i; - } - - return 0; -} - -Sprite::Sprite() { - _enabled = false; - _trails = 0; - _width = 0; - _ink = kInkTypeCopy; - _flags = 0; - _height = 0; - _castId = 0; - _constraint = 0; - _moveable = 0; - _castId = 0; - _backColor = 0; - _foreColor = 0; - _left = 0; - _right = 0; - _top = 0; - _bottom = 0; - _visible = false; - _movieRate = 0; - _movieTime = 0; - _startTime = 0; - _stopTime = 0; - _volume = 0; - _stretch = 0; - _type = kInactiveSprite; -} - -Sprite::Sprite(const Sprite &sprite) { - _enabled = sprite._enabled; - _castId = sprite._castId; - _flags = sprite._flags; - _trails = sprite._trails; - _ink = sprite._ink; - _width = sprite._width; - _height = sprite._height; - _startPoint.x = sprite._startPoint.x; - _startPoint.y = sprite._startPoint.y; - _backColor = sprite._backColor; - _foreColor = sprite._foreColor; - _left = sprite._left; - _right = sprite._right; - _top = sprite._top; - _bottom = sprite._bottom; - _visible = sprite._visible; - _movieRate = sprite._movieRate; - _movieTime = sprite._movieTime; - _stopTime = sprite._stopTime; - _volume = sprite._volume; - _stretch = sprite._stretch; - _type = sprite._type; -} - -Sprite::~Sprite() { - delete _cast; -} - } //End of namespace Director diff --git a/engines/director/score.h b/engines/director/score.h index 929dae666f..9d92de9538 100644 --- a/engines/director/score.h +++ b/engines/director/score.h @@ -36,11 +36,11 @@ namespace Director { class Lingo; class DirectorSound; +class Frame; +class Sprite; class Score; class DirectorEngine; -#define CHANNEL_COUNT 24 - enum CastType { kCastBitmap = 1, kCastFilmLoop, @@ -55,71 +55,6 @@ enum CastType { kCastScript }; -//Director v4 -enum SpriteType { - kInactiveSprite, //turns the sprite off - kBitmapSprite, - kRectangleSprite, - kRoundedRectangleSprite, - kOvalSprite, - kLineTopBottomSprite, //line from top left to bottom right - kLineBottomTopSprite, //line from bottom left to top right - kTextSprite, - kButtonSprite, - kCheckboxSprite, - kRadioButtonSprite, - kUndeterminedSprite = 16 //use castType property to examine the type of cast member associated with sprite -}; - -enum SpritePosition { - kSpritePositionUnk1 = 0, - kSpritePositionEnabled, - kSpritePositionUnk2, - kSpritePositionFlags = 4, - kSpritePositionCastId = 6, - kSpritePositionY = 8, - kSpritePositionX = 10, - kSpritePositionHeight = 12, - kSpritePositionWidth = 14 -}; - -enum MainChannelsPosition { - kScriptIdPosition = 0, - kSoundType1Position, - kTransFlagsPosition, - kTransChunkSizePosition, - kTempoPosition, - kTransTypePosition, - kSound1Position, - kSkipFrameFlagsPosition = 8, - kBlendPosition, - kSound2Position, - kSound2TypePosition = 11, - kPaletePosition = 15 -}; - -enum InkType { - kInkTypeCopy, - kInkTypeTransparent, - kInkTypeReverse, - kInkTypeGhost, - kInkTypeNotCopy, - kInkTypeNotTrans, - kInkTypeNotReverse, - kInkTypeNotGhost, - kInkTypeMatte, - kInkTypeMask, - //10-31 Not used (Lingo in a Nutshell) - kInkTypeBlend = 32, - kInkTypeAddPin, - kInkTypeAdd, - kInkTypeSubPin, - kInkTypeBackgndTrans, - kInkTypeLight, - kInkTypeSub, - kInkTypeDark -}; - enum ScriptType { kMovieScript = 0, kSpriteScript = 1, @@ -127,62 +62,6 @@ enum ScriptType { kMaxScriptType = 2 }; -enum TransitionType { - kTransNone, - kTransWipeRight, - kTransWipeLeft, - kTransWipeDown, - kTransWipeUp, - kTransCenterOutHorizontal, - kTransEdgesInHorizontal, - kTransCenterOutVertical, - kTransEdgesInVertical, - kTransCenterOutSquare, - kTransEdgesInSquare, - kTransPushLeft, - kTransPushRight, - kTransPushDown, - kTransPushUp, - kTransRevealUp, - kTransRevealUpRight, - kTransRevealRight, - kTransRevealDown, - kTransRevealDownRight, - kTransRevealDownLeft, - kTransRevealLeft, - kTransRevealUpLeft, - kTransDissolvePixelsFast, - kTransDissolveBoxyRects, - kTransDissolveBoxySquares, - kTransDissolvePatterns, - kTransRandomRows, - kTransRandomColumns, - kTransCoverDown, - kTransCoverDownLeft, - kTransCoverDownRight, - kTransCoverLeft, - kTransCoverRight, - kTransCoverUp, - kTransCoverUpLeft, - kTransCoverUpRight, - kTransTypeVenitianBlind, - kTransTypeCheckerboard, - kTransTypeStripsBottomBuildLeft, - kTransTypeStripsBottomBuildRight, - kTransTypeStripsLeftBuildDown, - kTransTypeStripsLeftBuildUp, - kTransTypeStripsRightBuildDown, - kTransTypeStripsRightBuildUp, - kTransTypeStripsTopBuildLeft, - kTransTypeStripsTopBuildRight, - kTransZoomOpen, - kTransZoomClose, - kTransVerticalBinds, - kTransDissolveBitsTrans, - kTransDissolvePixels, - kTransDissolveBits -}; - struct Cast { CastType type; Common::Rect initialRect; @@ -281,98 +160,6 @@ struct CastInfo { Common::String type; }; -struct PaletteInfo { - uint8 firstColor; - uint8 lastColor; - uint8 flags; - uint8 speed; - uint16 frameCount; -}; - -class Sprite { -public: - Sprite(); - Sprite(const Sprite &sprite); - ~Sprite(); - bool _enabled; - byte _castId; - InkType _ink; - uint16 _trails; - Cast *_cast; - uint16 _flags; - Common::Point _startPoint; - uint16 _width; - uint16 _height; - //TODO: default constraint = 0, if turned on, sprite is constrainted to the bounding rect - //As i know, constrainted != 0 only if sprite moveable - byte _constraint; - byte _moveable; - byte _backColor; - byte _foreColor; - uint16 _left; - uint16 _right; - uint16 _top; - uint16 _bottom; - byte _blend; - bool _visible; - SpriteType _type; - //Using in digital movie sprites - byte _movieRate; - uint16 _movieTime; - uint16 _startTime; - uint16 _stopTime; - byte _volume; - byte _stretch; - //Using in shape sprites - byte _lineSize; - //Using in text sprites - Common::String _editableText; -}; - -class Frame { -public: - Frame(DirectorEngine *vm); - Frame(const Frame &frame); - ~Frame(); - void readChannel(Common::SeekableSubReadStreamEndian &stream, uint16 offset, uint16 size); - void prepareFrame(Score *score); - uint16 getSpriteIDFromPos(Common::Point pos); - -private: - void playTransition(Score *score); - void playSoundChannel(); - void renderSprites(Graphics::ManagedSurface &surface, bool renderTrail); - void renderText(Graphics::ManagedSurface &surface, uint16 spriteId); - void renderButton(Graphics::ManagedSurface &surface, uint16 spriteId); - void readPaletteInfo(Common::SeekableSubReadStreamEndian &stream); - void readSprite(Common::SeekableSubReadStreamEndian &stream, uint16 offset, uint16 size); - void readMainChannels(Common::SeekableSubReadStreamEndian &stream, uint16 offset, uint16 size); - Image::ImageDecoder *getImageFrom(uint16 spriteID, int w, int h); - void drawBackgndTransSprite(Graphics::ManagedSurface &target, const Graphics::Surface &sprite, Common::Rect &drawRect); - void drawMatteSprite(Graphics::ManagedSurface &target, const Graphics::Surface &sprite, Common::Rect &drawRect); - void drawGhostSprite(Graphics::ManagedSurface &target, const Graphics::Surface &sprite, Common::Rect &drawRect); - void drawReverseSprite(Graphics::ManagedSurface &target, const Graphics::Surface &sprite, Common::Rect &drawRect); -public: - uint8 _actionId; - uint8 _transDuration; - uint8 _transArea; //1 - Whole Stage, 0 - Changing Area - uint8 _transChunkSize; - TransitionType _transType; - PaletteInfo *_palette; - uint8 _tempo; - - uint16 _sound1; - uint8 _soundType1; - uint16 _sound2; - uint8 _soundType2; - - uint8 _skipFrameFlag; - uint8 _blend; - Common::Array<Sprite *> _sprites; - Common::Array<Common::Rect > _drawRects; - DirectorEngine *_vm; -}; - struct Label { Common::String name; uint16 number; diff --git a/engines/director/sprite.cpp b/engines/director/sprite.cpp new file mode 100644 index 0000000000..7fd5b3d055 --- /dev/null +++ b/engines/director/sprite.cpp @@ -0,0 +1,85 @@ +/* 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 "director/director.h" +#include "director/score.h" +#include "director/sprite.h" + +namespace Director { + +Sprite::Sprite() { + _enabled = false; + _trails = 0; + _width = 0; + _ink = kInkTypeCopy; + _flags = 0; + _height = 0; + _castId = 0; + _constraint = 0; + _moveable = 0; + _castId = 0; + _backColor = 0; + _foreColor = 0; + _left = 0; + _right = 0; + _top = 0; + _bottom = 0; + _visible = false; + _movieRate = 0; + _movieTime = 0; + _startTime = 0; + _stopTime = 0; + _volume = 0; + _stretch = 0; + _type = kInactiveSprite; +} + +Sprite::Sprite(const Sprite &sprite) { + _enabled = sprite._enabled; + _castId = sprite._castId; + _flags = sprite._flags; + _trails = sprite._trails; + _ink = sprite._ink; + _width = sprite._width; + _height = sprite._height; + _startPoint.x = sprite._startPoint.x; + _startPoint.y = sprite._startPoint.y; + _backColor = sprite._backColor; + _foreColor = sprite._foreColor; + _left = sprite._left; + _right = sprite._right; + _top = sprite._top; + _bottom = sprite._bottom; + _visible = sprite._visible; + _movieRate = sprite._movieRate; + _movieTime = sprite._movieTime; + _stopTime = sprite._stopTime; + _volume = sprite._volume; + _stretch = sprite._stretch; + _type = sprite._type; +} + +Sprite::~Sprite() { + delete _cast; +} + +} //End of namespace Director diff --git a/engines/director/sprite.h b/engines/director/sprite.h new file mode 100644 index 0000000000..c66c66d6e4 --- /dev/null +++ b/engines/director/sprite.h @@ -0,0 +1,137 @@ +/* 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. + * + */ + +#ifndef DIRECTOR_SPRITE_H +#define DIRECTOR_SPRITE_H + +#include "common/rect.h" + +namespace Director { + +enum InkType { + kInkTypeCopy, + kInkTypeTransparent, + kInkTypeReverse, + kInkTypeGhost, + kInkTypeNotCopy, + kInkTypeNotTrans, + kInkTypeNotReverse, + kInkTypeNotGhost, + kInkTypeMatte, + kInkTypeMask, + //10-31 Not used (Lingo in a Nutshell) + kInkTypeBlend = 32, + kInkTypeAddPin, + kInkTypeAdd, + kInkTypeSubPin, + kInkTypeBackgndTrans, + kInkTypeLight, + kInkTypeSub, + kInkTypeDark +}; + +//Director v4 +enum SpriteType { + kInactiveSprite, //turns the sprite off + kBitmapSprite, + kRectangleSprite, + kRoundedRectangleSprite, + kOvalSprite, + kLineTopBottomSprite, //line from top left to bottom right + kLineBottomTopSprite, //line from bottom left to top right + kTextSprite, + kButtonSprite, + kCheckboxSprite, + kRadioButtonSprite, + kUndeterminedSprite = 16 //use castType property to examine the type of cast member associated with sprite +}; + +enum SpritePosition { + kSpritePositionUnk1 = 0, + kSpritePositionEnabled, + kSpritePositionUnk2, + kSpritePositionFlags = 4, + kSpritePositionCastId = 6, + kSpritePositionY = 8, + kSpritePositionX = 10, + kSpritePositionHeight = 12, + kSpritePositionWidth = 14 +}; + +enum MainChannelsPosition { + kScriptIdPosition = 0, + kSoundType1Position, + kTransFlagsPosition, + kTransChunkSizePosition, + kTempoPosition, + kTransTypePosition, + kSound1Position, + kSkipFrameFlagsPosition = 8, + kBlendPosition, + kSound2Position, + kSound2TypePosition = 11, + kPaletePosition = 15 +}; + +class Sprite { +public: + Sprite(); + Sprite(const Sprite &sprite); + ~Sprite(); + bool _enabled; + byte _castId; + InkType _ink; + uint16 _trails; + Cast *_cast; + uint16 _flags; + Common::Point _startPoint; + uint16 _width; + uint16 _height; + //TODO: default constraint = 0, if turned on, sprite is constrainted to the bounding rect + //As i know, constrainted != 0 only if sprite moveable + byte _constraint; + byte _moveable; + byte _backColor; + byte _foreColor; + uint16 _left; + uint16 _right; + uint16 _top; + uint16 _bottom; + byte _blend; + bool _visible; + SpriteType _type; + //Using in digital movie sprites + byte _movieRate; + uint16 _movieTime; + uint16 _startTime; + uint16 _stopTime; + byte _volume; + byte _stretch; + //Using in shape sprites + byte _lineSize; + //Using in text sprites + Common::String _editableText; +}; + +} //End of namespace Director + +#endif |