aboutsummaryrefslogtreecommitdiff
path: root/engines/gob/coktelvideo.cpp
diff options
context:
space:
mode:
authorSven Hesse2008-12-03 22:14:47 +0000
committerSven Hesse2008-12-03 22:14:47 +0000
commit353a239bdb824e57e67745752d2df15dc3ae0687 (patch)
tree27bfa145527e25cba72d21d0ab9db1be20e5f938 /engines/gob/coktelvideo.cpp
parent1edc1789b1af4a3e5aaaa3e44d5e6683585db8db (diff)
downloadscummvm-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/gob/coktelvideo.cpp')
-rw-r--r--engines/gob/coktelvideo.cpp182
1 files changed, 173 insertions, 9 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