/* 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 "common/config-manager.h" #include "common/events.h" #include "common/memstream.h" #include "engines/util.h" #include "graphics/font.h" #include "graphics/palette.h" #include "graphics/macgui/macfontmanager.h" #include "graphics/macgui/macwindowmanager.h" #include "director/score.h" #include "director/frame.h" #include "director/archive.h" #include "director/sound.h" #include "director/sprite.h" #include "director/lingo/lingo.h" namespace Director { static byte defaultPalette[768] = { 0, 0, 0, 17, 17, 17, 34, 34, 34, 68, 68, 68, 85, 85, 85, 119, 119, 119, 136, 136, 136, 170, 170, 170, 187, 187, 187, 221, 221, 221, 238, 238, 238, 0, 0, 17, 0, 0, 34, 0, 0, 68, 0, 0, 85, 0, 0, 119, 0, 0, 136, 0, 0, 170, 0, 0, 187, 0, 0, 221, 0, 0, 238, 0, 17, 0, 0, 34, 0, 0, 68, 0, 0, 85, 0, 0, 119, 0, 0, 136, 0, 0, 170, 0, 0, 187, 0, 0, 221, 0, 0, 238, 0, 17, 0, 0, 34, 0, 0, 68, 0, 0, 85, 0, 0, 119, 0, 0, 136, 0, 0, 170, 0, 0, 187, 0, 0, 221, 0, 0, 238, 0, 0, 0, 0, 51, 0, 0, 102, 0, 0, 153, 0, 0, 204, 0, 0, 255, 0, 51, 0, 0, 51, 51, 0, 51, 102, 0, 51, 153, 0, 51, 204, 0, 51, 255, 0, 102, 0, 0, 102, 51, 0, 102, 102, 0, 102, 153, 0, 102, 204, 0, 102, 255, 0, 153, 0, 0, 153, 51, 0, 153, 102, 0, 153, 153, 0, 153, 204, 0, 153, 255, 0, 204, 0, 0, 204, 51, 0, 204, 102, 0, 204, 153, 0, 204, 204, 0, 204, 255, 0, 255, 0, 0, 255, 51, 0, 255, 102, 0, 255, 153, 0, 255, 204, 0, 255, 255, 51, 0, 0, 51, 0, 51, 51, 0, 102, 51, 0, 153, 51, 0, 204, 51, 0, 255, 51, 51, 0, 51, 51, 51, 51, 51, 102, 51, 51, 153, 51, 51, 204, 51, 51, 255, 51, 102, 0, 51, 102, 51, 51, 102, 102, 51, 102, 153, 51, 102, 204, 51, 102, 255, 51, 153, 0, 51, 153, 51, 51, 153, 102, 51, 153, 153, 51, 153, 204, 51, 153, 255, 51, 204, 0, 51, 204, 51, 51, 204, 102, 51, 204, 153, 51, 204, 204, 51, 204, 255, 51, 255, 0, 51, 255, 51, 51, 255, 102, 51, 255, 153, 51, 255, 204, 51, 255, 255, 102, 0, 0, 102, 0, 51, 102, 0, 102, 102, 0, 153, 102, 0, 204, 102, 0, 255, 102, 51, 0, 102, 51, 51, 102, 51, 102, 102, 51, 153, 102, 51, 204, 102, 51, 255, 102, 102, 0, 102, 102, 51, 102, 102, 102, 102, 102, 153, 102, 102, 204, 102, 102, 255, 102, 153, 0, 102, 153, 51, 102, 153, 102, 102, 153, 153, 102, 153, 204, 102, 153, 255, 102, 204, 0, 102, 204, 51, 102, 204, 102, 102, 204, 153, 102, 204, 204, 102, 204, 255, 102, 255, 0, 102, 255, 51, 102, 255, 102, 102, 255, 153, 102, 255, 204, 102, 255, 255, 153, 0, 0, 153, 0, 51, 153, 0, 102, 153, 0, 153, 153, 0, 204, 153, 0, 255, 153, 51, 0, 153, 51, 51, 153, 51, 102, 153, 51, 153, 153, 51, 204, 153, 51, 255, 153, 102, 0, 153, 102, 51, 153, 102, 102, 153, 102, 153, 153, 102, 204, 153, 102, 255, 153, 153, 0, 153, 153, 51, 153, 153, 102, 153, 153, 153, 153, 153, 204, 153, 153, 255, 153, 204, 0, 153, 204, 51, 153, 204, 102, 153, 204, 153, 153, 204, 204, 153, 204, 255, 153, 255, 0, 153, 255, 51, 153, 255, 102, 153, 255, 153, 153, 255, 204, 153, 255, 255, 204, 0, 0, 204, 0, 51, 204, 0, 102, 204, 0, 153, 204, 0, 204, 204, 0, 255, 204, 51, 0, 204, 51, 51, 204, 51, 102, 204, 51, 153, 204, 51, 204, 204, 51, 255, 204, 102, 0, 204, 102, 51, 204, 102, 102, 204, 102, 153, 204, 102, 204, 204, 102, 255, 204, 153, 0, 204, 153, 51, 204, 153, 102, 204, 153, 153, 204, 153, 204, 204, 153, 255, 204, 204, 0, 204, 204, 51, 204, 204, 102, 204, 204, 153, 204, 204, 204, 204, 204, 255, 204, 255, 0, 204, 255, 51, 204, 255, 102, 204, 255, 153, 204, 255, 204, 204, 255, 255, 255, 0, 0, 255, 0, 51, 255, 0, 102, 255, 0, 153, 255, 0, 204, 255, 0, 255, 255, 51, 0, 255, 51, 51, 255, 51, 102, 255, 51, 153, 255, 51, 204, 255, 51, 255, 255, 102, 0, 255, 102, 51, 255, 102, 102, 255, 102, 153, 255, 102, 204, 255, 102, 255, 255, 153, 0, 255, 153, 51, 255, 153, 102, 255, 153, 153, 255, 153, 204, 255, 153, 255, 255, 204, 0, 255, 204, 51, 255, 204, 102, 255, 204, 153, 255, 204, 204, 255, 204, 255, 255, 255, 0, 255, 255, 51, 255, 255, 102, 255, 255, 153, 255, 255, 204, 255, 255, 255 }; void DirectorEngine::testFont() { int x = 10; int y = 10; int w = 640; int h = 480; initGraphics(w, h, true); g_system->getPaletteManager()->setPalette(defaultPalette, 0, 256); Graphics::ManagedSurface surface; surface.create(w, h); surface.clear(255); const char *text = "d"; for (int i = 9; i <= 40; i++) { Graphics::MacFont macFont(Graphics::kMacFontNewYork, i); const Graphics::Font *font = _wm->_fontMan->getFont(macFont); int width = font->getStringWidth(text); Common::Rect bbox = font->getBoundingBox(text, x, y, w); surface.frameRect(bbox, 15); font->drawString(&surface, text, x, y, width, 0); x += width + 1; } g_system->copyRectToScreen(surface.getPixels(), surface.pitch, 0, 0, w, h); Common::Event event; while (true) { if (g_system->getEventManager()->pollEvent(event)) if (event.type == Common::EVENT_QUIT) break; g_system->updateScreen(); g_system->delayMillis(10); } } Score::Score(DirectorEngine *vm, Archive *archive) { _vm = vm; _surface = new Graphics::ManagedSurface; _trailSurface = new Graphics::ManagedSurface; _movieArchive = archive; _lingo = _vm->getLingo(); _soundManager = _vm->getSoundManager(); _lingo->processEvent(kEventPrepareMovie, 0); _movieScriptCount = 0; _labels = NULL; _font = NULL; _versionMinor = _versionMajor = 0; _currentFrameRate = 20; _castArrayStart = _castArrayEnd = 0; _currentFrame = 0; _nextFrameTime = 0; _flags = 0; _stopPlay = false; _stageColor = 0; if (archive->hasResource(MKTAG('M','C','N','M'), 0)) { _macName = archive->getName(MKTAG('M','C','N','M'), 0).c_str(); } else { _macName = archive->getFileName(); } if (archive->hasResource(MKTAG('V','W','L','B'), 1024)) { loadLabels(*archive->getResource(MKTAG('V','W','L','B'), 1024)); } } void Score::loadArchive() { Common::Array clutList = _movieArchive->getResourceIDList(MKTAG('C','L','U','T')); if (clutList.size() > 1) warning("More than one palette was found (%d)", clutList.size()); if (clutList.size() == 0) { warning("CLUT resource not found, using default Mac palette"); g_system->getPaletteManager()->setPalette(defaultPalette, 0, 256); _vm->setPalette(defaultPalette, 256); } else { Common::SeekableSubReadStreamEndian *pal = _movieArchive->getResource(MKTAG('C', 'L', 'U', 'T'), clutList[0]); loadPalette(*pal); g_system->getPaletteManager()->setPalette(_vm->getPalette(), 0, _vm->getPaletteColorCount()); } assert(_movieArchive->hasResource(MKTAG('V','W','S','C'), 1024)); assert(_movieArchive->hasResource(MKTAG('V','W','C','F'), 1024)); loadFrames(*_movieArchive->getResource(MKTAG('V','W','S','C'), 1024)); loadConfig(*_movieArchive->getResource(MKTAG('V','W','C','F'), 1024)); if (_vm->getVersion() < 4) { assert(_movieArchive->hasResource(MKTAG('V','W','C','R'), 1024)); loadCastDataD2(*_movieArchive->getResource(MKTAG('V','W','C','R'), 1024)); } if (_movieArchive->hasResource(MKTAG('V','W','A','C'), 1024)) { loadActions(*_movieArchive->getResource(MKTAG('V','W','A','C'), 1024)); } if (_movieArchive->hasResource(MKTAG('V','W','F','I'), 1024)) { loadFileInfo(*_movieArchive->getResource(MKTAG('V','W','F','I'), 1024)); } if (_movieArchive->hasResource(MKTAG('V','W','F','M'), 1024)) { loadFontMap(*_movieArchive->getResource(MKTAG('V','W','F','M'), 1024)); } Common::Array vwci = _movieArchive->getResourceIDList(MKTAG('V','W','C','I')); if (vwci.size() > 0) { for (Common::Array::iterator iterator = vwci.begin(); iterator != vwci.end(); ++iterator) loadCastInfo(*_movieArchive->getResource(MKTAG('V','W','C','I'), *iterator), *iterator); } Common::Array cast = _movieArchive->getResourceIDList(MKTAG('C','A','S','t')); if (cast.size() > 0) { for (Common::Array::iterator iterator = cast.begin(); iterator != cast.end(); ++iterator) loadCastData(*_movieArchive->getResource(MKTAG('C','A','S','t'), *iterator), *iterator); } Common::Array stxt = _movieArchive->getResourceIDList(MKTAG('S','T','X','T')); if (stxt.size() > 0) { loadScriptText(*_movieArchive->getResource(MKTAG('S','T','X','T'), *stxt.begin())); } } Score::~Score() { if (_surface) _surface->free(); if (_trailSurface) _trailSurface->free(); delete _surface; delete _trailSurface; if (_movieArchive) _movieArchive->close(); delete _font; delete _labels; } void Score::loadPalette(Common::SeekableSubReadStreamEndian &stream) { uint16 steps = stream.size() / 6; uint16 index = (steps * 3) - 1; uint16 _paletteColorCount = steps; byte *_palette = new byte[index + 1]; for (uint8 i = 0; i < steps; i++) { _palette[index - 2] = stream.readByte(); stream.readByte(); _palette[index - 1] = stream.readByte(); stream.readByte(); _palette[index] = stream.readByte(); stream.readByte(); index -= 3; } _vm->setPalette(_palette, _paletteColorCount); } void Score::loadFrames(Common::SeekableSubReadStreamEndian &stream) { uint32 size = stream.readUint32(); size -= 4; if (_vm->getVersion() > 3) { uint32 unk1 = stream.readUint32(); uint32 unk2 = stream.readUint32(); uint16 unk3 = stream.readUint16(); uint16 unk4 = stream.readUint16(); uint16 unk5 = stream.readUint16(); uint16 unk6 = stream.readUint16(); size -= 16; warning("STUB: Score::loadFrames. unk1: %x unk2: %x unk3: %x unk4: %x unk5: %x unk6: %x", unk1, unk2, unk3, unk4, unk5, unk6); //Unknown, some bytes - constant (refer to contuinity). } uint16 channelSize; uint16 channelOffset; Frame *initial = new Frame(_vm); _frames.push_back(initial); // This is a representation of the channelData. It gets overridden // partically by channels, hence we keep it and read the score from left to right // // TODO Merge it with shared cast byte channelData[kChannelDataSize]; memset(channelData, 0, kChannelDataSize); while (size != 0) { uint16 frameSize = stream.readUint16(); debugC(kDebugLoading, 8, "++++ score frame %d (frameSize %d) size %d", _frames.size(), frameSize, size); size -= frameSize; frameSize -= 2; Frame *frame = new Frame(_vm); while (frameSize != 0) { if (_vm->getVersion() < 4) { channelSize = stream.readByte() * 2; channelOffset = stream.readByte() * 2; frameSize -= channelSize + 2; } else { channelSize = stream.readUint16(); channelOffset = stream.readUint16(); frameSize -= channelSize + 4; } assert(channelOffset + channelSize < kChannelDataSize); stream.read(&channelData[channelOffset], channelSize); } Common::MemoryReadStreamEndian *str = new Common::MemoryReadStreamEndian(channelData, ARRAYSIZE(channelData), stream.isBE()); frame->readChannels(str); delete str; _frames.push_back(frame); } //remove initial frame _frames.remove_at(0); } void Score::loadConfig(Common::SeekableSubReadStreamEndian &stream) { /*uint16 unk1 = */ stream.readUint16(); /*ver1 = */ stream.readUint16(); _movieRect = Score::readRect(stream); _castArrayStart = stream.readUint16(); _castArrayEnd = stream.readUint16(); _currentFrameRate = stream.readByte(); stream.skip(9); _stageColor = stream.readUint16(); } void Score::readVersion(uint32 rid) { _versionMinor = rid & 0xffff; _versionMajor = rid >> 16; debug("Version: %d.%d", _versionMajor, _versionMinor); } void Score::loadCastDataD2(Common::SeekableSubReadStreamEndian &stream) { debugC(1, kDebugLoading, "Score::loadCastData(). start: %d, end: %d", _castArrayStart, _castArrayEnd); for (uint16 id = _castArrayStart; id <= _castArrayEnd; id++) { byte size = stream.readByte(); if (size == 0) continue; uint8 castType = stream.readByte(); switch (castType) { case kCastBitmap: _casts[id] = new BitmapCast(stream); _casts[id]->type = kCastBitmap; break; case kCastText: _casts[id] = new TextCast(stream); _casts[id]->type = kCastText; break; case kCastShape: _casts[id] = new ShapeCast(stream); _casts[id]->type = kCastShape; break; case kCastButton: _casts[id] = new ButtonCast(stream); _casts[id]->type = kCastButton; break; default: warning("Unhandled cast type: %d", castType); stream.skip(size - 1); break; } } //Set cast pointers to sprites for (uint16 i = 0; i < _frames.size(); i++) { for (uint16 j = 0; j < _frames[i]->_sprites.size(); j++) { byte castId = _frames[i]->_sprites[j]->_castId; if (_casts.contains(castId)) _frames[i]->_sprites[j]->_cast = _casts.find(castId)->_value; } } } void Score::loadCastData(Common::SeekableSubReadStreamEndian &stream, uint16 id) { // d4+ variant if (stream.size() == 0) return; if (stream.size() < 26) { warning("CAST data id %d is too small", id); return; } uint castId = id - 1024; uint32 size1, size2, size3, castType; byte blob[3]; if (_vm->getVersion() < 5) { size1 = stream.readUint16(); size2 = stream.readUint32(); size3 = 0; castType = stream.readByte(); stream.read(blob, 3); } else { // FIXME: only the cast type and the strings are good castType = stream.readUint32(); size2 = stream.readUint32(); size3 = stream.readUint32(); size1 = stream.readUint32(); assert(size1 == 0x14); size1 = 0; blob[0] = blob[1] = blob[2] = 0; } warning("type: %x", castType); Score::readRect(stream); Score::readRect(stream); //member.initialRect = readRect(data) //member.boundingRect = readRect(data) //member.regX = 0 // FIXME: HACK //member.regY = 0 // FIXME: HACK byte *data = (byte *)calloc(size1, 1); stream.read(data, size1); Common::hexdump(data, size1); free(data); if (size2) { uint32 entryType = 0; Common::Array castStrings = loadStrings(stream, entryType); CastInfo *ci = new CastInfo(); ci->script = castStrings[0]; ci->name = castStrings[1]; ci->directory = castStrings[2]; ci->fileName = castStrings[3]; ci->type = castStrings[4]; _castsInfo[id] = ci; } if (size3) warning("size3: %x", size3); } void Score::loadLabels(Common::SeekableSubReadStreamEndian &stream) { _labels = new Common::SortedArray