aboutsummaryrefslogtreecommitdiff
path: root/engines/gob
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
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')
-rw-r--r--engines/gob/coktelvideo.cpp182
-rw-r--r--engines/gob/coktelvideo.h24
-rw-r--r--engines/gob/dataio.cpp4
-rw-r--r--engines/gob/game.cpp16
-rw-r--r--engines/gob/game_v2.cpp4
-rw-r--r--engines/gob/inter_v4.cpp4
-rw-r--r--engines/gob/videoplayer.cpp42
-rw-r--r--engines/gob/videoplayer.h7
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();