diff options
author | Sven Hesse | 2008-12-03 22:14:47 +0000 |
---|---|---|
committer | Sven Hesse | 2008-12-03 22:14:47 +0000 |
commit | 353a239bdb824e57e67745752d2df15dc3ae0687 (patch) | |
tree | 27bfa145527e25cba72d21d0ab9db1be20e5f938 /engines | |
parent | 1edc1789b1af4a3e5aaaa3e44d5e6683585db8db (diff) | |
download | scummvm-rg350-353a239bdb824e57e67745752d2df15dc3ae0687.tar.gz scummvm-rg350-353a239bdb824e57e67745752d2df15dc3ae0687.tar.bz2 scummvm-rg350-353a239bdb824e57e67745752d2df15dc3ae0687.zip |
Preliminary support for extra data and scripts in video files (urgh, this is so...vile).
Used in The Last Dynasty, which now plays a bit further (the video sequences, at least)
svn-id: r35227
Diffstat (limited to 'engines')
-rw-r--r-- | engines/gob/coktelvideo.cpp | 182 | ||||
-rw-r--r-- | engines/gob/coktelvideo.h | 24 | ||||
-rw-r--r-- | engines/gob/dataio.cpp | 4 | ||||
-rw-r--r-- | engines/gob/game.cpp | 16 | ||||
-rw-r--r-- | engines/gob/game_v2.cpp | 4 | ||||
-rw-r--r-- | engines/gob/inter_v4.cpp | 4 | ||||
-rw-r--r-- | engines/gob/videoplayer.cpp | 42 | ||||
-rw-r--r-- | engines/gob/videoplayer.h | 7 |
8 files changed, 268 insertions, 15 deletions
diff --git a/engines/gob/coktelvideo.cpp b/engines/gob/coktelvideo.cpp index 415790e67b..6dd8e8c7b0 100644 --- a/engines/gob/coktelvideo.cpp +++ b/engines/gob/coktelvideo.cpp @@ -880,8 +880,10 @@ bool Vmd::load(Common::SeekableReadStream &stream) { uint16 handle = _stream->readUint16LE(); _version = _stream->readUint16LE(); + // 0x4 (4) + // Version checking - if ((headerLength != 814) || (handle != 0) || (_version != 1)) { + if (headerLength != 814) { warning("VMD Version incorrect (%d, %d, %d)", headerLength, handle, _version); unload(); return false; @@ -889,31 +891,62 @@ bool Vmd::load(Common::SeekableReadStream &stream) { _framesCount = _stream->readUint16LE(); + // 0x6 (6) + _x = _stream->readSint16LE(); _y = _stream->readSint16LE(); _width = _stream->readSint16LE(); _height = _stream->readSint16LE(); + + // 0xE (14) + if ((_width != 0) && (_height != 0)) { _hasVideo = true; _features |= kFeaturesVideo; } else _hasVideo = false; + if (_width > 320) { + if (!(_version & 4)) { + _version |= 4; + handle = 0; + } + } + + if (handle == 0) { + // _field_463 = 1; + } else if (handle == 1) { + // _field_463 = 0; + } else if (handle == 2) { + // _field_463 = 2; + } else { + warning("VMD Version incorrect (%d, %d, %d)", headerLength, handle, _version); + unload(); + return false; + } + _flags = _stream->readUint16LE(); _partsPerFrame = _stream->readUint16LE(); _firstFramePos = _stream->readUint32LE(); _stream->skip(4); // Unknown + // 0x1A (26) + _stream->read((byte *) _palette, 768); + // 0x31A (794) + _frameDataSize = _stream->readUint32LE(); _vidBufferSize = _stream->readUint32LE(); + // 0x322 (802) + if (_hasVideo) { - if ((_frameDataSize == 0) || (_frameDataSize > 1048576)) + _vidBufferSize = _frameDataSize = 312200; +/* if ((_frameDataSize == 0) || (_frameDataSize > 1048576)) _frameDataSize = _width * _height + 500; if ((_vidBufferSize == 0) || (_vidBufferSize > 1048576)) - _vidBufferSize = _frameDataSize; + _vidBufferSize = _frameDataSize;*/ _frameData = new byte[_frameDataSize]; assert(_frameData); @@ -929,6 +962,8 @@ bool Vmd::load(Common::SeekableReadStream &stream) { _soundFlags = _stream->readUint16LE(); _hasSound = (_soundFreq != 0); + // 0x32A (810) + if (_hasSound) { _features |= kFeaturesSound; @@ -956,6 +991,8 @@ bool Vmd::load(Common::SeekableReadStream &stream) { _frameInfoOffset = _stream->readUint32LE(); + int numExtraData = 0; + _stream->seek(_frameInfoOffset); _frames = new Frame[_framesCount]; for (uint16 i = 0; i < _framesCount; i++) { @@ -964,6 +1001,8 @@ bool Vmd::load(Common::SeekableReadStream &stream) { _frames[i].offset = _stream->readUint32LE(); } for (uint16 i = 0; i < _framesCount; i++) { + bool separator = false; + for (uint16 j = 0; j < _partsPerFrame; j++) { _frames[i].parts[j].type = (PartType) _stream->readByte(); @@ -984,6 +1023,13 @@ bool Vmd::load(Common::SeekableReadStream &stream) { _stream->skip(1); // Unknown _frames[i].parts[j].flags = _stream->readByte(); + } else if (_frames[i].parts[j].type == kPartTypeExtraData) { + if (!separator) + numExtraData++; + _stream->skip(10); + } else if (_frames[i].parts[j].type == kPartTypeSeparator) { + separator = true; + _stream->skip(10); } else { // Unknow type _stream->skip(10); @@ -992,6 +1038,45 @@ bool Vmd::load(Common::SeekableReadStream &stream) { } } + if (numExtraData == 0) + return true; + + _extraData.reserve(numExtraData); + + numExtraData = 0; + + uint32 ssize = _stream->size(); + for (uint16 i = 0; i < _framesCount; i++) { + _stream->seek(_frames[i].offset); + + for (uint16 j = 0; j < _partsPerFrame; j++) { + if (_frames[i].parts[j].type == kPartTypeSeparator) + break; + + if (_frames[i].parts[j].type == kPartTypeExtraData) { + ExtraData data; + + data.offset = _stream->pos() + 20; + data.size = _frames[i].parts[j].size; + data.realSize = _stream->readUint32LE(); + _stream->read(data.name, 16); + data.name[15] = '\0'; + + _stream->skip(_frames[i].parts[j].size - 20); + + if ((((uint32) data.realSize) >= ssize) || (data.name[0] == 0)) + continue; + + warning("ExtraData %d: %d.%d, %d, %d, %d, %s", _extraData.size(), i, j, + data.offset, data.size, data.realSize, data.name); + + _extraData.push_back(data); + + } else + _stream->skip(_frames[i].parts[j].size); + } + } + return true; } @@ -1057,15 +1142,16 @@ CoktelVideo::State Vmd::nextFrame() { void Vmd::clear(bool del) { Imd::clear(del); - if (del) { + if (del) delete[] _frames; - } _hasVideo = true; _partsPerFrame = 0; _frames = 0; + _extraData.clear(); + _soundBytesPerSample = 1; _soundStereo = 0; } @@ -1294,9 +1380,46 @@ uint32 Vmd::renderFrame(int16 left, int16 top, int16 right, int16 bottom) { imdVidMemBak += sW; imdVidMem = imdVidMemBak; } - } else { - warning("Unkown frame rendering method %d (0x%X)", type, type); - return 0; + } else if (type == 0x42) { // Whole quarter-wide block + for (int i = 0; i < height; i++) { + imdVidMemBak = imdVidMem; + + for (int j = 0; j < width; j += 4, imdVidMem += 4, srcPtr++) + memset(imdVidMem, *srcPtr, 4); + + imdVidMemBak += sW; + imdVidMem = imdVidMemBak; + } + } else if ((type & 0xF) == 2) { // Whole half-high block + for (; height > 1; height -= 2, imdVidMem += sW + sW, srcPtr += width) { + memcpy(imdVidMem, srcPtr, width); + memcpy(imdVidMem + sW, srcPtr, width); + } + if (height == -1) + memcpy(imdVidMem, srcPtr, width); + } else { // Sparse half-high block + imdVidMemBak = imdVidMem; + for (int i = 0; i < height; i += 2) { + pixWritten = 0; + while (pixWritten < width) { + pixCount = *srcPtr++; + if (pixCount & 0x80) { // Data + pixCount = MIN((pixCount & 0x7F) + 1, width - pixWritten); + memcpy(imdVidMem, srcPtr, pixCount); + memcpy(imdVidMem + sW, srcPtr, pixCount); + + pixWritten += pixCount; + imdVidMem += pixCount; + srcPtr += pixCount; + } else { // "Hole" + pixCount = (pixCount + 1) % 256; + pixWritten += pixCount; + imdVidMem += pixCount; + } + } + imdVidMemBak += sW + sW; + imdVidMem = imdVidMemBak; + } } return 1; @@ -1387,7 +1510,7 @@ bool Vmd::getAnchor(int16 frame, uint16 partType, for (i = 0; i < _partsPerFrame; i++) { byte type = _stream->readByte(); - if ((type == 0) || (type == partType)) + if ((type == kPartTypeSeparator) || (type == partType)) break; _stream->skip(15); @@ -1410,4 +1533,45 @@ bool Vmd::getAnchor(int16 frame, uint16 partType, return true; } +bool Vmd::hasExtraData(const char *fileName) const { + for (uint i = 0; i < _extraData.size(); i++) + if (!scumm_stricmp(_extraData[i].name, fileName)) + return true; + + return false; +} + +Common::MemoryReadStream *Vmd::getExtraData(const char *fileName) { + uint i = 0; + + for (i = 0; i < _extraData.size(); i++) + if (!scumm_stricmp(_extraData[i].name, fileName)) + break; + + if (i >= _extraData.size()) + return 0; + + if ((_extraData[i].size - 20) != _extraData[i].realSize) { + warning("Vmd::getExtraData(): Sizes for \"%s\" differ! (%d, %d)", + fileName, (_extraData[i].size - 20), _extraData[i].realSize); + return 0; + } + + byte *data = (byte *) malloc(_extraData[i].realSize); + + _stream->seek(_extraData[i].offset); + if (_stream->ioFailed() || (((uint32) _stream->pos()) != _extraData[i].offset)) { + warning("Vmd::getExtraData(): Can't seek to offset %d to get extra data file \"%s\"", + _extraData[i].offset, fileName); + return 0; + } + + _stream->read(data, _extraData[i].realSize); + + Common::MemoryReadStream *stream = + new Common::MemoryReadStream(data, _extraData[i].realSize, true); + + return stream; +} + } // End of namespace Gob diff --git a/engines/gob/coktelvideo.h b/engines/gob/coktelvideo.h index 348e5e3ab1..72df93ab56 100644 --- a/engines/gob/coktelvideo.h +++ b/engines/gob/coktelvideo.h @@ -27,6 +27,7 @@ #define GOB_COKTELVIDEO_H #include "common/stream.h" +#include "common/array.h" #include "sound/mixer.h" #include "sound/audiostream.h" @@ -119,6 +120,11 @@ public: virtual bool getAnchor(int16 frame, uint16 partType, int16 &x, int16 &y, int16 &width, int16 &height) = 0; + /** Returns whether that extra data file exists */ + virtual bool hasExtraData(const char *fileName) const = 0; + /** Returns an extra data file */ + virtual Common::MemoryReadStream *getExtraData(const char *fileName) = 0; + /** Load a video out of a stream. */ virtual bool load(Common::SeekableReadStream &stream) = 0; /** Unload the currently loaded video. */ @@ -201,6 +207,9 @@ public: bool getAnchor(int16 frame, uint16 partType, int16 &x, int16 &y, int16 &width, int16 &height) { return false; } + bool hasExtraData(const char *fileName) const { return false; } + Common::MemoryReadStream *getExtraData(const char *fileName) { return 0; } + void setFrameRate(int16 frameRate); bool load(Common::SeekableReadStream &stream); @@ -295,6 +304,9 @@ public: bool getAnchor(int16 frame, uint16 partType, int16 &x, int16 &y, int16 &width, int16 &height); + bool hasExtraData(const char *fileName) const; + Common::MemoryReadStream *getExtraData(const char *fileName); + bool load(Common::SeekableReadStream &stream); void unload(); @@ -306,9 +318,17 @@ public: protected: enum PartType { + kPartTypeSeparator = 0, kPartTypeAudio = 1, - kPartTypeVideo = 2 + kPartTypeVideo = 2, + kPartTypeExtraData = 3 }; + struct ExtraData { + char name[16]; + uint32 offset; + uint32 size; + uint32 realSize; + } PACKED_STRUCT; struct Part { PartType type; uint32 size; @@ -334,6 +354,8 @@ protected: uint16 _partsPerFrame; Frame *_frames; + Common::Array<ExtraData> _extraData; + byte _soundBytesPerSample; byte _soundStereo; // (0: mono, 1: old-style stereo, 2: new-style stereo) diff --git a/engines/gob/dataio.cpp b/engines/gob/dataio.cpp index d154a01de9..a2bb730870 100644 --- a/engines/gob/dataio.cpp +++ b/engines/gob/dataio.cpp @@ -312,8 +312,10 @@ int16 DataIO::seekChunk(int16 handle, int32 pos, int16 from) { _isCurrentSlot[index] = false; if (from == SEEK_SET) _chunkPos[index] = pos; - else + else if (from == SEEK_CUR) _chunkPos[index] += pos; + else if (from == SEEK_END) + _chunkPos[index] = _chunkSize[index] - pos; return _chunkPos[index]; } diff --git a/engines/gob/game.cpp b/engines/gob/game.cpp index 73fa820fa0..b544b2c234 100644 --- a/engines/gob/game.cpp +++ b/engines/gob/game.cpp @@ -34,6 +34,7 @@ #include "gob/parse.h" #include "gob/draw.h" #include "gob/mult.h" +#include "gob/videoplayer.h" #include "gob/sound/sound.h" namespace Gob { @@ -394,8 +395,19 @@ int32 Game::loadTotFile(const char *path) { _vm->_dataIO->closeData(handle); size = _vm->_dataIO->getDataSize(path); _totFileData = _vm->_dataIO->getData(path); - } else - _totFileData = 0; + } else { + Common::MemoryReadStream *videoExtraData = _vm->_vidPlayer->getExtraData(path); + + if (videoExtraData) { + warning("Found \"%s\" in video file", path); + + size = videoExtraData->size(); + _totFileData = new byte[size]; + videoExtraData->read(_totFileData, size); + delete videoExtraData; + } else + _totFileData = 0; + } return size; } diff --git a/engines/gob/game_v2.cpp b/engines/gob/game_v2.cpp index 9d09fac425..28de420467 100644 --- a/engines/gob/game_v2.cpp +++ b/engines/gob/game_v2.cpp @@ -106,6 +106,9 @@ void Game_v2::playTot(int16 skipPlay) { break; totSize = loadTotFile(_curTotFile); + + _vm->_vidPlayer->primaryClose(); + if (_totFileData == 0) { _vm->_draw->blitCursor(); _vm->_inter->_terminate = 2; @@ -269,7 +272,6 @@ void Game_v2::playTot(int16 skipPlay) { } } - _vm->_vidPlayer->primaryClose(); if (_totToLoad[0] == 0) break; diff --git a/engines/gob/inter_v4.cpp b/engines/gob/inter_v4.cpp index fb895dd5b2..1921f4c6fd 100644 --- a/engines/gob/inter_v4.cpp +++ b/engines/gob/inter_v4.cpp @@ -834,6 +834,7 @@ void Inter_v4::o4_playVmdOrMusic() { close = false; if (lastFrame == -1) { close = true; + } else if (lastFrame == -2) { } else if (lastFrame == -3) { _vm->_mult->_objects[startFrame].pAnimData->animation = -startFrame - 1; @@ -878,7 +879,8 @@ void Inter_v4::o4_playVmdOrMusic() { } if (startFrame == -2) { - startFrame = lastFrame = 0; + startFrame = 0; + lastFrame = -1; close = false; } diff --git a/engines/gob/videoplayer.cpp b/engines/gob/videoplayer.cpp index e36dc19596..4ae9dfdd53 100644 --- a/engines/gob/videoplayer.cpp +++ b/engines/gob/videoplayer.cpp @@ -124,6 +124,20 @@ int16 VideoPlayer::Video::getDefaultY() const { return _defaultY; } +bool VideoPlayer::Video::hasExtraData(const char *fileName) const { + if (!_video) + return false; + + return _video->hasExtraData(fileName); +} + +Common::MemoryReadStream *VideoPlayer::Video::getExtraData(const char *fileName) { + if (!_video) + return 0; + + return _video->getExtraData(fileName); +} + CoktelVideo::State VideoPlayer::Video::nextFrame() { if (_video) _state = _video->nextFrame(); @@ -445,6 +459,16 @@ const VideoPlayer::Video *VideoPlayer::getVideoBySlot(int slot) const { return 0; } +VideoPlayer::Video *VideoPlayer::getVideoBySlot(int slot) { + if (slot < 0) { + if (_primaryVideo->isOpen()) + return _primaryVideo; + } else if (((uint) slot) < _videoSlots.size() && _videoSlots[slot]) + return _videoSlots[slot]; + + return 0; +} + uint16 VideoPlayer::getFlags(int slot) const { const Video *video = getVideoBySlot(slot); @@ -508,6 +532,24 @@ int16 VideoPlayer::getDefaultY(int slot) const { return 0; } +bool VideoPlayer::hasExtraData(const char *fileName, int slot) const { + const Video *video = getVideoBySlot(slot); + + if (video) + return video->hasExtraData(fileName); + + return false; +} + +Common::MemoryReadStream *VideoPlayer::getExtraData(const char *fileName, int slot) { + Video *video = getVideoBySlot(slot); + + if (video) + return video->getExtraData(fileName); + + return 0; +} + bool VideoPlayer::doPlay(int16 frame, int16 breakKey, uint16 palCmd, int16 palStart, int16 palEnd, int16 palFrame, int16 endFrame) { diff --git a/engines/gob/videoplayer.h b/engines/gob/videoplayer.h index b7aa7313b0..295bb62fd3 100644 --- a/engines/gob/videoplayer.h +++ b/engines/gob/videoplayer.h @@ -80,6 +80,9 @@ public: int16 getDefaultX(int slot = -1) const; int16 getDefaultY(int slot = -1) const; + bool hasExtraData(const char *fileName, int slot = -1) const; + Common::MemoryReadStream *getExtraData(const char *fileName, int slot = -1); + void writeVideoInfo(const char *videoFile, int16 varX, int16 varY, int16 varFrames, int16 varWidth, int16 varHeight); @@ -104,6 +107,9 @@ private: int16 getDefaultX() const; int16 getDefaultY() const; + bool hasExtraData(const char *fileName) const; + Common::MemoryReadStream *getExtraData(const char *fileName); + CoktelVideo::State nextFrame(); private: @@ -129,6 +135,7 @@ private: bool findFile(char *fileName, Type &which); const Video *getVideoBySlot(int slot = -1) const; + Video *getVideoBySlot(int slot = -1); int getNextFreeSlot(); |