aboutsummaryrefslogtreecommitdiff
path: root/engines/gob
diff options
context:
space:
mode:
authorSven Hesse2007-07-31 18:16:33 +0000
committerSven Hesse2007-07-31 18:16:33 +0000
commit2e9ca7bf85cdaf71f009c689a0aae6cd14e8f710 (patch)
treea379cd851af49d7d2d3df30837d25d54fdfa567a /engines/gob
parentcd20f09a9d8085d1082313fd1d58c87deeb30333 (diff)
downloadscummvm-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/gob')
-rw-r--r--engines/gob/coktelvideo.cpp497
-rw-r--r--engines/gob/coktelvideo.h90
-rw-r--r--engines/gob/dataio.cpp17
-rw-r--r--engines/gob/inter_v4.cpp4
-rw-r--r--engines/gob/videoplayer.cpp5
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)