diff options
author | Sven Hesse | 2007-07-31 18:16:33 +0000 |
---|---|---|
committer | Sven Hesse | 2007-07-31 18:16:33 +0000 |
commit | 2e9ca7bf85cdaf71f009c689a0aae6cd14e8f710 (patch) | |
tree | a379cd851af49d7d2d3df30837d25d54fdfa567a /engines | |
parent | cd20f09a9d8085d1082313fd1d58c87deeb30333 (diff) | |
download | scummvm-rg350-2e9ca7bf85cdaf71f009c689a0aae6cd14e8f710.tar.gz scummvm-rg350-2e9ca7bf85cdaf71f009c689a0aae6cd14e8f710.tar.bz2 scummvm-rg350-2e9ca7bf85cdaf71f009c689a0aae6cd14e8f710.zip |
Still partly broken/stubby VMD playing
svn-id: r28363
Diffstat (limited to 'engines')
-rw-r--r-- | engines/gob/coktelvideo.cpp | 497 | ||||
-rw-r--r-- | engines/gob/coktelvideo.h | 90 | ||||
-rw-r--r-- | engines/gob/dataio.cpp | 17 | ||||
-rw-r--r-- | engines/gob/inter_v4.cpp | 4 | ||||
-rw-r--r-- | engines/gob/videoplayer.cpp | 5 |
5 files changed, 463 insertions, 150 deletions
diff --git a/engines/gob/coktelvideo.cpp b/engines/gob/coktelvideo.cpp index e7eebe602a..0d59bf4993 100644 --- a/engines/gob/coktelvideo.cpp +++ b/engines/gob/coktelvideo.cpp @@ -58,13 +58,16 @@ bool Imd::load(Common::SeekableReadStream &stream) { // Rest header _features = _stream->readByte(); _framesCount = _stream->readUint16LE(); - _x = _stream->readUint16LE(); - _y = _stream->readUint16LE(); - _width = _stream->readUint16LE(); - _height = _stream->readUint16LE(); + _x = _stream->readSint16LE(); + _y = _stream->readSint16LE(); + _width = _stream->readSint16LE(); + _height = _stream->readSint16LE(); _flags = _stream->readUint16LE(); _firstFramePos = _stream->readUint16LE(); + // IMDs always have video + _features |= kFeaturesVideo; + // Palette _stream->read((byte *) _palette, 768); @@ -77,10 +80,10 @@ bool Imd::load(Common::SeekableReadStream &stream) { return false; } if (_stdX != 0) { - _stdX = _stream->readUint16LE(); - _stdY = _stream->readUint16LE(); - _stdWidth = _stream->readUint16LE(); - _stdHeight = _stream->readUint16LE(); + _stdX = _stream->readSint16LE(); + _stdY = _stream->readSint16LE(); + _stdWidth = _stream->readSint16LE(); + _stdHeight = _stream->readSint16LE(); _features |= kFeaturesStdCoords; } else _stdX = -1; @@ -92,7 +95,7 @@ bool Imd::load(Common::SeekableReadStream &stream) { if (_version >= 4) { framesPosPos = _stream->readUint32LE(); if (framesPosPos != 0) { - _framesPos = new int32[_framesCount]; + _framesPos = new uint32[_framesCount]; assert(_framesPos); _features |= kFeaturesFramesPos; } @@ -105,9 +108,9 @@ bool Imd::load(Common::SeekableReadStream &stream) { // Sound if (_features & kFeaturesSound) { - _soundFreq = _stream->readUint16LE(); + _soundFreq = _stream->readSint16LE(); _soundSliceSize = _stream->readUint16LE(); - _soundSlicesCount = _stream->readUint16LE(); + _soundSlicesCount = _stream->readSint16LE(); if (_soundFreq < 0) _soundFreq = -_soundFreq; @@ -158,10 +161,10 @@ bool Imd::load(Common::SeekableReadStream &stream) { _frameCoords = new Coord[_framesCount]; assert(_frameCoords); for (int i = 0; i < _framesCount; i++) { - _frameCoords[i].left = _stream->readUint16LE(); - _frameCoords[i].top = _stream->readUint16LE(); - _frameCoords[i].right = _stream->readUint16LE(); - _frameCoords[i].bottom = _stream->readUint16LE(); + _frameCoords[i].left = _stream->readSint16LE(); + _frameCoords[i].top = _stream->readSint16LE(); + _frameCoords[i].right = _stream->readSint16LE(); + _frameCoords[i].bottom = _stream->readSint16LE(); } } @@ -186,9 +189,9 @@ void Imd::unload() { void Imd::setXY(int16 x, int16 y) { // Adjusting the standard coordinates if (_stdX != -1) { - if (x != -1) + if (x >= 0) _stdX = _stdX - _x + x; - if (y != -1) + if (y >= 0) _stdY = _stdY - _y + y; } @@ -196,11 +199,11 @@ void Imd::setXY(int16 x, int16 y) { if (_frameCoords) { for (int i = 0; i < _framesCount; i++) { if (_frameCoords[i].left != -1) { - if (x != -1) { + if (x >= 0) { _frameCoords[i].left = _frameCoords[i].left - _x + x; _frameCoords[i].right = _frameCoords[i].right - _x + x; } - if (y != -1) { + if (y >= 0) { _frameCoords[i].top = _frameCoords[i].top - _y + y; _frameCoords[i].bottom = _frameCoords[i].bottom - _y + y; } @@ -208,9 +211,9 @@ void Imd::setXY(int16 x, int16 y) { } } - if (x != -1) + if (x >= 0) _x = x; - if (y != -1) + if (y >= 0) _y = y; } @@ -259,7 +262,7 @@ void Imd::disableSound() { _mixer = 0; } -void Imd::seekFrame(int16 frame, int16 whence, bool restart) { +void Imd::seekFrame(int32 frame, int16 whence, bool restart) { if (!_stream) // Nothing to do return; @@ -272,7 +275,7 @@ void Imd::seekFrame(int16 frame, int16 whence, bool restart) { else if (whence != SEEK_SET) return; - if ((frame >= _framesCount) || (frame == _curFrame)) + if ((frame < 0) || (frame >= _framesCount) || (frame == _curFrame)) // Nothing to do return; @@ -293,7 +296,7 @@ void Imd::seekFrame(int16 frame, int16 whence, bool restart) { error("Frame %d is not directly accessible", frame); // Seek - _stream->seek(framePos, SEEK_SET); + _stream->seek(framePos); _curFrame = frame; } @@ -426,7 +429,7 @@ void Imd::clear(bool del) { _lastFrameTime = 0; } -CoktelVideo::State Imd::processFrame(int16 frame) { +CoktelVideo::State Imd::processFrame(uint16 frame) { State state; uint32 cmd = 0; int16 xBak, yBak, heightBak, widthBak; @@ -440,7 +443,7 @@ CoktelVideo::State Imd::processFrame(int16 frame) { if (frame != _curFrame) { state.flags |= kStateSeeked; - seekFrame(frame, SEEK_SET); + seekFrame(frame); } state.left = xBak = _x; @@ -559,7 +562,7 @@ CoktelVideo::State Imd::processFrame(int16 frame) { // Jump to frame if (cmd == 0xFFFD) { - frame = _stream->readUint16LE(); + frame = _stream->readSint16LE(); if (_framesPos) { _curFrame = frame; _stream->seek(_framesPos[frame], SEEK_SET); @@ -612,7 +615,7 @@ CoktelVideo::State Imd::processFrame(int16 frame) { state.flags |= _frameData[0]; } else - state.flags |= kStateNoData; + state.flags |= kStateNoVideoData; } while (hasNextCmd); @@ -640,95 +643,6 @@ CoktelVideo::State Imd::processFrame(int16 frame) { return state; } -CoktelVideo::State Imd::peekFrame(int16 frame) { - State state; - uint32 posBak; - uint32 tmp; - uint16 cmd; - int16 frameBak; - - if (!_stream) { - state.flags = kStateBreak; - return state; - } - - posBak = _stream->pos(); - frameBak = _curFrame; - - if (_curFrame != frame) { - state.flags |= kStateSeeked; - seekFrame(frame, SEEK_SET); - } - - do { - if (frame != 0) { - if (_stdX != -1) - state.flags |= kStateStdCoords; - if (_frameCoords && (_frameCoords[frame].left != -1)) - state.flags |= kStateFrameCoords; - } - - cmd = _stream->readUint16LE(); - - if ((cmd & 0xFFF8) == 0xFFF0) { - if (cmd == 0xFFF0) { - _stream->seek(2, SEEK_CUR); - cmd = _stream->readUint16LE(); - } - - if (cmd == 0xFFF1) { - state.flags = kStateBreak; - continue; - } else if (cmd == 0xFFF2) { // Skip (16 bit) - cmd = _stream->readUint16LE(); - _stream->seek(cmd, SEEK_CUR); - state.flags = kStateBreak; - continue; - } else if (cmd == 0xFFF3) { // Skip (32 bit) - tmp = _stream->readUint32LE(); - _stream->seek(cmd, SEEK_CUR); - state.flags = kStateBreak; - continue; - } - } - - // Jump to frame - if (cmd == 0xFFFD) { - frame = _stream->readUint16LE(); - if (_framesPos) { - _stream->seek(_framesPos[frame], SEEK_SET); - state.flags |= kStateJump; - continue; - } - break; - } - - // Next sound slice data - if (cmd == 0xFF00) { - _stream->seek(_soundSliceSize, SEEK_CUR); - cmd = _stream->readUint16LE(); - // Initial sound data (all slices) - } else if (cmd == 0xFF01) { - _stream->seek(_soundSliceSize * _soundSlicesCount, SEEK_CUR); - cmd = _stream->readUint16LE(); - } - - // Frame video data - if (cmd != 0) { - _stream->read(_frameData, 5); - state.flags |= _frameData[0]; - } else - state.flags |= kStateNoData; - - break; - - } while (true); - - _stream->seek(posBak, SEEK_SET); - _curFrame = frameBak; - return state; -} - uint32 Imd::renderFrame() { if (!_frameData || (_width <= 0) || (_height <= 0)) return 0; @@ -763,10 +677,10 @@ uint32 Imd::renderFrame() { srcPtr = _vidBuffer; type &= 0x7F; if ((type == 2) && (imdW == sW)) { - frameUncompressor(imdVidMem, dataPtr); + deLZ77(imdVidMem, dataPtr); return retVal; } else - frameUncompressor(srcPtr, dataPtr); + deLZ77(srcPtr, dataPtr); } uint16 pixCount, pixWritten; @@ -845,7 +759,7 @@ uint32 Imd::renderFrame() { return retVal; } -void Imd::frameUncompressor(byte *dest, byte *src) { +void Imd::deLZ77(byte *dest, byte *src) { int i; byte buf[4370]; uint16 chunkLength; @@ -857,7 +771,7 @@ void Imd::frameUncompressor(byte *dest, byte *src) { uint8 chunkCount; bool mode; - frameLength = READ_LE_UINT16(src); + frameLength = READ_LE_UINT32(src); src += 4; if ((READ_LE_UINT16(src) == 0x1234) && (READ_LE_UINT16(src + 2) == 0x5678)) { @@ -932,4 +846,345 @@ void Imd::frameUncompressor(byte *dest, byte *src) { } } +Vmd::Vmd() { + clear(false); +} + +Vmd::~Vmd() { + clear(); +} + +bool Vmd::load(Common::SeekableReadStream &stream) { + unload(); + + _stream = &stream; + + uint16 headerLength = _stream->readUint16LE(); + uint16 handle = _stream->readUint16LE(); + _version = _stream->readUint16LE(); + + // Version checking + if ((headerLength != 814) || (handle != 0) || (_version != 1)) { + warning("IMD Version incorrect (%d, %d, %d)", headerLength, handle, _version); + unload(); + return false; + } + + _framesCount = _stream->readUint16LE(); + + warning("# of frames: %d", _framesCount); + + _x = _stream->readSint16LE(); + _y = _stream->readSint16LE(); + _width = _stream->readSint16LE(); + _height = _stream->readSint16LE(); + if ((_width != 0) && (_height != 0)) { + _hasVideo = true; + _features |= kFeaturesVideo; + + warning("%dx%d+%d+%d", _width, _height, _x, _y); + + } else + _hasVideo = false; + + _flags = _stream->readUint16LE(); + _partsPerFrame = _stream->readUint16LE(); + _firstFramePos = _stream->readUint32LE(); + uint32 unknown1 = _stream->readUint32LE(); + + warning("flags: %d (0x%X), #parts: %d, firstFramePos: %d, U1: %d (0x%X)", + _flags, _flags, _partsPerFrame, _firstFramePos, unknown1, unknown1); + + _stream->read((byte *) _palette, 768); + + _frameDataSize = _stream->readUint32LE(); + _vidBufferSize = _stream->readUint32LE(); + + if (_hasVideo) { + if (_frameDataSize == 0) + _frameDataSize = _width * _height + 500; + if (_vidBufferSize) + _vidBufferSize = _frameDataSize; + + _frameData = new byte[_frameDataSize]; + assert(_frameData); + memset(_frameData, 0, _frameDataSize); + _vidBuffer = new byte[_vidBufferSize]; + assert(_vidBuffer); + memset(_vidBuffer, 0, _vidBufferSize); + warning("Sizes: frameData: %d, vidBuffer: %d", _frameDataSize, _vidBufferSize); + } + + _soundFreq = _stream->readSint16LE(); + _soundSliceSize = _stream->readUint16LE(); + _soundSlicesCount = _stream->readSint16LE(); + uint16 soundFlags = _stream->readUint16LE(); + _hasSound = (_soundFreq != 0); + + if (_hasSound) { + _features |= kFeaturesSound; + + _soundSliceLength = 1000 / (_soundFreq / _soundSliceSize); + _frameLength = _soundSliceLength; + + _soundStage = 1; + + _audioStream = Audio::makeAppendableAudioStream(_soundFreq, 0); + + warning("Sound: Freq: %d, # slices %d, slideSize: %d, flags: %d (0x%X), sliceLen = %d", + _soundFreq, _soundSlicesCount, _soundSliceSize, soundFlags, soundFlags, _soundSliceLength); + + } else + _frameLength = 1000 / 12; // 12 FPS for a video without sound + + uint32 frameInfoOffset = _stream->readUint32LE(); + + warning("frameInfoOffset: %d", frameInfoOffset); + + _stream->seek(frameInfoOffset); + _frames = new Frame[_framesCount]; + for (uint16 i = 0; i < _framesCount; i++) { + _frames[i].parts = new Part[_partsPerFrame]; + _stream->skip(2); + _frames[i].offset = _stream->readUint32LE(); + } + for (uint16 i = 0; i < _framesCount; i++) { + for (uint16 j = 0; j < _partsPerFrame; j++) { + _frames[i].parts[j].type = (PartType) _stream->readByte(); + uint16 Unknown3 = _stream->readByte(); + _frames[i].parts[j].size = _stream->readUint32LE(); + if (_frames[i].parts[j].type == kPartTypeAudio) { + _frames[i].parts[j].flags = _stream->readByte(); + _stream->skip(9); + warning("%d.%d (%d): Audio: %d (0x%X), %d (0x%X)", + i, j, _frames[i].parts[j].size, + Unknown3, Unknown3, _frames[i].parts[j].flags, _frames[i].parts[j].flags); + + } else if (_frames[i].parts[j].type == kPartTypeVideo) { + _frames[i].parts[j].left = _stream->readUint16LE(); + _frames[i].parts[j].top = _stream->readUint16LE(); + _frames[i].parts[j].right = _stream->readUint16LE(); + _frames[i].parts[j].bottom = _stream->readUint16LE(); + uint16 Unknown4 = _stream->readByte(); + _frames[i].parts[j].flags = _stream->readByte(); + warning("%d.%d (%d): Video: %d (0x%X), %d+%d+%d+%d, %d (0x%X), %d (0x%X)", + i, j, _frames[i].parts[j].size, + Unknown3, Unknown3, _frames[i].parts[j].left, + _frames[i].parts[j].top, _frames[i].parts[j].right, + _frames[i].parts[j].bottom, Unknown4, Unknown4, + _frames[i].parts[j].flags, _frames[i].parts[j].flags); + + } else { + warning("VMD: Unknown frame part type found (%d.%d: %d, %d)", + i, j, _frames[i].parts[j].type, _frames[i].parts[j].size); + _stream->skip(10); +// unload(); +// return false; + } + } + } + + return true; +} + +void Vmd::unload() { + clear(); +} + +void Vmd::setXY(int16 x, int16 y) { + + for (int i = 0; i < _framesCount; i++) { + for (int j = 0; j < _partsPerFrame; j++) { + + if (_frames[i].parts[j].type == kPartTypeVideo) { + if (x >= 0) { + _frames[i].parts[j].left = _frames[i].parts[j].left - _x + x; + _frames[i].parts[j].right = _frames[i].parts[j].right - _x + x; + } + if (y >= 0) { + _frames[i].parts[j].top = _frames[i].parts[j].top - _y + y; + _frames[i].parts[j].bottom = _frames[i].parts[j].bottom - _y + y; + } + } + + } + } + + if (x >= 0) + _x = x; + if (y >= 0) + _y = y; +} + +void Vmd::seekFrame(int32 frame, int16 whence, bool restart) { + if (!_stream) + // Nothing to do + return; + + // Find the frame to which to seek + if (whence == SEEK_CUR) + frame += _curFrame; + else if (whence == SEEK_END) + frame = _framesCount - frame - 1; + else if (whence != SEEK_SET) + return; + + if ((frame < 0) || (frame >= _framesCount)) + // Nothing to do + return; + + // Seek + _stream->seek(_frames[frame].offset); + _curFrame = frame; +} + +CoktelVideo::State Vmd::nextFrame() { + State state; + + state = processFrame(_curFrame); + _curFrame++; + return state; +} + +void Vmd::clear(bool del) { + Imd::clear(del); + + if (del) { + delete[] _frames; + } + + _hasVideo = true; + _partsPerFrame = 0; + _frames = 0; +} + +CoktelVideo::State Vmd::processFrame(uint16 frame) { + State state; + int16 xBak, yBak, heightBak, widthBak; + bool startSound = false; + + seekFrame(frame); + + state.flags |= kStateNoVideoData; + state.left = -1; + + for (uint16 i = 0; i < _partsPerFrame; i++) { + Part &part = _frames[frame].parts[i]; + + if (part.type == kPartTypeAudio) { + byte *soundBuf; + + // Next sound slice data + if (part.flags == 1) { + + if (_soundEnabled) { + soundBuf = new byte[part.size]; + assert(soundBuf); + + _stream->read(soundBuf, part.size); + unsignedToSigned(soundBuf, part.size); + + _audioStream->queueBuffer(soundBuf, part.size); + } else + _stream->skip(part.size); + + // Initial sound data (all slices) + } else if (part.flags == 2) { + + if (_soundEnabled) { + uint32 U = _stream->readUint32LE(); + + warning("Mask? %d (0x%X)", U, U); + + soundBuf = new byte[part.size - 4]; + assert(soundBuf); + + _stream->read(soundBuf, part.size - 4); + unsignedToSigned(soundBuf, part.size - 4); + + _audioStream->queueBuffer(soundBuf, part.size - 4); + + if (_soundStage == 1) { + startSound = true; + } + + } else + _stream->skip(part.size); + + // Empty sound slice + } else if (part.flags == 3) { + + if (_soundEnabled && (part.size > 0)) { + soundBuf = new byte[part.size]; + assert(soundBuf); + + memset(soundBuf, 0, part.size); + + _audioStream->queueBuffer(soundBuf, part.size); + } else + _stream->skip(part.size); + } + + } else if (part.type == kPartTypeVideo) { + state.flags &= ~kStateNoVideoData; + + if (state.left == -1) { + state.left = _x = part.left; + state.top = _y = part.top; + state.right = _width = part.right; + state.bottom = _height = part.bottom; + _width -= _x - 1; + _height -= _y - 1; + } else { + _x = part.left; + _y = part.top; + _width = part.right - (_x - 1); + _height = part.bottom - (_y - 1); + state.left = MIN(state.left, part.left); + state.top = MIN(state.top, part.top); + state.right = MAX(state.right, part.right); + state.bottom = MAX(state.bottom, part.bottom); + } + + if (part.flags & 2) { + uint8 index = _stream->readByte(); + uint8 count = _stream->readByte(); + + _stream->read(_palette + index * 3, count + 1); + _stream->skip((255 - count) * 3); + + state.flags |= kStatePalette; + } + + _stream->read(_frameData, part.size); + state.flags |= renderFrame(); + } else { + warning("Unknown frame part type %d, size %d (%d of %d)", part.type, part.size, i + 1, _partsPerFrame); + _stream->skip(part.size); + } + } + + if (startSound && _soundEnabled) { + _mixer->playInputStream(Audio::Mixer::kSFXSoundType, &_audioHandle, _audioStream); + _soundStartTime = g_system->getMillis(); + _skipFrames = 0; + _soundStage = 2; + } + + _x = xBak; + _y = yBak; + _width = widthBak; + _height = heightBak; + + if ((_curFrame == (_framesCount - 1)) && (_soundStage == 2)) { + _audioStream->finish(); + _mixer->stopHandle(_audioHandle); + _audioStream = 0; + _soundStage = 0; + } + + _lastFrameTime = g_system->getMillis(); + return state; +} + } // End of namespace Gob diff --git a/engines/gob/coktelvideo.h b/engines/gob/coktelvideo.h index 5788d024af..678fde3967 100644 --- a/engines/gob/coktelvideo.h +++ b/engines/gob/coktelvideo.h @@ -48,7 +48,9 @@ public: /** Has general standard coordinates. */ kFeaturesStdCoords = 0x100, /** Has a frame positions table. */ - kFeaturesFramesPos = 0x200 + kFeaturesFramesPos = 0x200, + /** Has video. */ + kFeaturesVideo = 0x400 }; enum StateFlags { @@ -60,7 +62,7 @@ public: /** Updated according to the specific frame coordinates. */ kStateFrameCoords = 0x400, /** Got no frame data. */ - kStateNoData = 0x800, + kStateNoVideoData = 0x800, /** Updated according to the general standard coordinates. */ kStateStdCoords = 0x1000, /** Had to explicitely seek to the frame. */ @@ -80,6 +82,8 @@ public: int16 bottom; /** Set accordingly to what was done. */ uint32 flags; + + State() : left(0), top(0), right(0), bottom(0), flags(0) { } }; virtual ~CoktelVideo() { } @@ -95,9 +99,13 @@ public: /** Returns the height of the video. */ virtual int16 getHeight() const = 0; /** Returns the number of frames the loaded video has. */ - virtual int16 getFramesCount() const = 0; - /** Returns the current frame number. */ - virtual int16 getCurrentFrame() const = 0; + virtual uint16 getFramesCount() const = 0; + /** Returns the current frame number. + * + * This is the current frame after the last nextFrame()-call, + * i.e. it's 0 after loading, 1 after the first nextFrame()-call, etc.. + */ + virtual uint16 getCurrentFrame() const = 0; /** Returns the frame rate. */ virtual int16 getFrameRate() const = 0; /** Returns the number of frames the video lags behind the audio. */ @@ -128,12 +136,10 @@ public: * @param whence The offset from whence the frame is given. * @param restart Restart the video to reach an otherwise inaccessible frame? */ - virtual void seekFrame(int16 frame, int16 whence = SEEK_SET, bool restart = false) = 0; + virtual void seekFrame(int32 frame, int16 whence = SEEK_SET, bool restart = false) = 0; /** Render the next frame. */ virtual State nextFrame() = 0; - /** Look at what a frame would do/have, without actually rendering the frame. */ - virtual State peekFrame(int16 frame) = 0; /** Wait for the frame to end. */ virtual void waitEndFrame() = 0; @@ -160,8 +166,8 @@ public: int16 getY() const { return _y; } int16 getWidth() const { return _width; } int16 getHeight() const { return _height; } - int16 getFramesCount() const { return _framesCount; } - int16 getCurrentFrame() const { return _curFrame; } + uint16 getFramesCount() const { return _framesCount; } + uint16 getCurrentFrame() const { return _curFrame; } int16 getFrameRate() const { if (_hasSound) return 1000 / _soundSliceLength; return 12; } uint32 getSyncLag() const { return _skipFrames; } const byte *getPalette() const { return _palette; } @@ -176,10 +182,9 @@ public: void enableSound(Audio::Mixer &mixer); void disableSound(); - void seekFrame(int16 frame, int16 whence = SEEK_SET, bool restart = false); + void seekFrame(int32 frame, int16 whence = SEEK_SET, bool restart = false); State nextFrame(); - State peekFrame(int16 frame); void waitEndFrame(); void copyCurrentFrame(byte *dest, uint16 x, uint16 y, uint16 width, int16 transp = -1); @@ -193,17 +198,17 @@ protected: } PACKED_STRUCT; Common::SeekableReadStream *_stream; - uint8 _version; + uint16 _version; uint16 _features; - int16 _flags; + uint16 _flags; int16 _x, _y, _width, _height; int16 _stdX, _stdY, _stdWidth, _stdHeight; - int16 _framesCount, _curFrame; - int32 *_framesPos; - int32 _firstFramePos; + uint16 _framesCount, _curFrame; + uint32 *_framesPos; + uint32 _firstFramePos; Coord *_frameCoords; - int32 _frameDataSize, _vidBufferSize; + uint32 _frameDataSize, _vidBufferSize; byte *_frameData, *_vidBuffer; byte _palette[768]; @@ -238,9 +243,54 @@ protected: void deleteVidMem(bool del = true); void clear(bool del = true); - State processFrame(int16 frame); + State processFrame(uint16 frame); uint32 renderFrame(); - void frameUncompressor(byte *dest, byte *src); + void deLZ77(byte *dest, byte *src); +}; + +class Vmd : public Imd { +public: + Vmd(); + ~Vmd(); + + bool load(Common::SeekableReadStream &stream); + void unload(); + + void setXY(int16 x, int16 y); + + void seekFrame(int32 frame, int16 whence = SEEK_SET, bool restart = false); + + State nextFrame(); + +protected: + enum PartType { + kPartTypeAudio = 1, + kPartTypeVideo = 2 + }; + struct Part { + PartType type; + uint32 size; + int16 left; + int16 top; + int16 right; + int16 bottom; + byte flags; + } PACKED_STRUCT; + struct Frame { + uint32 offset; + Part *parts; + + Frame() : parts(0) { } + ~Frame() { delete[] parts; } + } PACKED_STRUCT; + + bool _hasVideo; + uint16 _partsPerFrame; + Frame *_frames; + + void clear(bool del = true); + + State processFrame(uint16 frame); }; } // End of namespace Gob diff --git a/engines/gob/dataio.cpp b/engines/gob/dataio.cpp index 3c5dbed575..361627caf4 100644 --- a/engines/gob/dataio.cpp +++ b/engines/gob/dataio.cpp @@ -103,11 +103,20 @@ uint32 DataStream::read(void *dataPtr, uint32 dataSize) { if (_stream) return _stream->read(dataPtr, dataSize); - int32 res = _io->readChunk(_handle, (byte *) dataPtr, dataSize); - if (res >= 0) - return res; + if ((_handle < 50) || (_handle >= 128)) + return _io->file_getHandle(_handle)->read((byte *) dataPtr, dataSize); + + byte *data = (byte *) dataPtr; + uint32 haveRead = 0; + while (dataSize > 0x3FFF) { + _io->readChunk(_handle, (byte *) data, 0x3FFF); + dataSize -= 0x3FFF; + data += 0x3FFF; + haveRead += 0x3FFF; + } + _io->readChunk(_handle, (byte *) data, dataSize); - return _io->file_getHandle(_handle)->read((byte *) dataPtr, dataSize); + return haveRead + dataSize; } DataIO::DataIO(GobEngine *vm) : _vm(vm) { diff --git a/engines/gob/inter_v4.cpp b/engines/gob/inter_v4.cpp index 1297b03fbf..81f53757a3 100644 --- a/engines/gob/inter_v4.cpp +++ b/engines/gob/inter_v4.cpp @@ -742,12 +742,12 @@ void Inter_v4::o4_playVmdOrMusic() { close = true; } else if (lastFrame == -3) { warning("Woodruff Stub: Video/Music command -3: Play background video %s", fileName); - return; +// return; } else if (lastFrame == -4) { warning("Woodruff Stub: Video/Music command -4: Play background video %s", fileName); return; } else if (lastFrame == -5) { - warning("Woodruff Stub: Video/Music command -5"); + warning("Woodruff Stub: Video/Music command -5: Stop background music"); return; } else if (lastFrame == -6) { warning("Woodruff Stub: Video/Music command -6: Load background video %s", fileName); diff --git a/engines/gob/videoplayer.cpp b/engines/gob/videoplayer.cpp index d048b6084d..e72354a169 100644 --- a/engines/gob/videoplayer.cpp +++ b/engines/gob/videoplayer.cpp @@ -119,9 +119,7 @@ bool VideoPlayer::openVideo(const char *video, int16 x, int16 y, int16 flags, Ty if (which == kVideoTypeIMD) { _video = new Imd(); } else if (which == kVideoTypeVMD) { - warning("STUB: %s", fileName); - closeVideo(); - return false; + _video = new Vmd(); } else { warning("Couldn't open video \"%s\": Invalid video Type", fileName); closeVideo(); @@ -161,6 +159,7 @@ void VideoPlayer::play(int16 startFrame, int16 lastFrame, int16 breakKey, if (!_video) return; + breakKey = 27; if (startFrame < 0) startFrame = _video->getCurrentFrame(); if (lastFrame < 0) |