aboutsummaryrefslogtreecommitdiff
path: root/engines
diff options
context:
space:
mode:
authorPaul Gilbert2013-06-22 11:57:51 -0400
committerPaul Gilbert2013-06-22 11:57:51 -0400
commitc4a56dbdb87ef347106ae9a16426df5306d8a91f (patch)
treed81c2ec5c619e3f41cbf601c2c3dccb6864d9116 /engines
parent8c2b956120c9f11e6aa89753aa5dcdee8d2f1d7a (diff)
downloadscummvm-rg350-c4a56dbdb87ef347106ae9a16426df5306d8a91f.tar.gz
scummvm-rg350-c4a56dbdb87ef347106ae9a16426df5306d8a91f.tar.bz2
scummvm-rg350-c4a56dbdb87ef347106ae9a16426df5306d8a91f.zip
VOYEUR: Implemented RL2 video decoder
Diffstat (limited to 'engines')
-rw-r--r--engines/voyeur/animation.cpp279
-rw-r--r--engines/voyeur/animation.h100
-rw-r--r--engines/voyeur/graphics.cpp4
-rw-r--r--engines/voyeur/graphics.h1
-rw-r--r--engines/voyeur/module.mk1
-rw-r--r--engines/voyeur/voyeur.cpp35
-rw-r--r--engines/voyeur/voyeur.h2
7 files changed, 421 insertions, 1 deletions
diff --git a/engines/voyeur/animation.cpp b/engines/voyeur/animation.cpp
new file mode 100644
index 0000000000..b2bcb2a35c
--- /dev/null
+++ b/engines/voyeur/animation.cpp
@@ -0,0 +1,279 @@
+/* ScummVM - Graphic Adventure Engine
+ *
+ * ScummVM is the legal property of its developers, whose names
+ * are too numerous to list here. Please refer to the COPYRIGHT
+ * file distributed with this source distribution.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ */
+
+#include "voyeur/animation.h"
+#include "common/system.h"
+#include "graphics/surface.h"
+
+namespace Video {
+
+RL2Decoder::RL2Decoder() {
+}
+
+RL2Decoder::~RL2Decoder() {
+ close();
+}
+
+bool RL2Decoder::loadStream(Common::SeekableReadStream *stream) {
+ close();
+
+ stream->seek(8);
+
+ // Check RL2 magic number
+ uint32 signature = stream->readUint32LE();
+ if (signature != 0x33564c52 /* RLV3 */ && signature != 0x32564c52 /* RLV2 */) {
+ warning("RL2Decoder::loadStream(): attempted to load non-RL2 data (type = 0x%08X)", signature);
+ return false;
+ }
+
+ addTrack(new RL2VideoTrack(stream));
+ return true;
+}
+
+const Common::List<Common::Rect> *RL2Decoder::getDirtyRects() const {
+ const Track *track = getTrack(0);
+
+ if (track)
+ return ((const RL2VideoTrack *)track)->getDirtyRects();
+
+ return 0;
+}
+
+void RL2Decoder::clearDirtyRects() {
+ Track *track = getTrack(0);
+
+ if (track)
+ ((RL2VideoTrack *)track)->clearDirtyRects();
+}
+
+void RL2Decoder::copyDirtyRectsToBuffer(uint8 *dst, uint pitch) {
+ Track *track = getTrack(0);
+
+ if (track)
+ ((RL2VideoTrack *)track)->copyDirtyRectsToBuffer(dst, pitch);
+}
+
+RL2Decoder::RL2VideoTrack::RL2VideoTrack(Common::SeekableReadStream *stream) {
+ _fileStream = stream;
+
+ stream->seek(4);
+ uint32 backSize = stream->readUint32LE();
+ assert(backSize == 0 || backSize == (320 * 200));
+
+ stream->seek(16);
+ _frameCount = stream->readUint16LE();
+
+ // Calculate the frame rate
+ stream->seek(22);
+ int soundRate = stream->readUint16LE();
+ int rate = stream->readUint16LE();
+ stream->skip(2);
+ int defSoundSize = stream->readUint16LE();
+
+ int fps = (soundRate > 0) ? rate / defSoundSize : 11025 / 1103;
+ _frameDelay = 1000 / fps;
+
+ _surface = new Graphics::Surface();
+ _surface->create(320, 200, Graphics::PixelFormat::createFormatCLUT8());
+ if (backSize == 0) {
+ _backSurface = NULL;
+ } else {
+ _backSurface = new Graphics::Surface();
+ _backSurface->create(320, 200, Graphics::PixelFormat::createFormatCLUT8());
+
+ stream->seek(0x324);
+ _fileStream->read((byte *)_backSurface->pixels, 320 * 200);
+ }
+
+ stream->seek(30);
+ _videoBase = stream->readUint16LE();
+ stream->seek(36);
+ _palette = new byte[3 * 256];
+ stream->read(_palette, 256 * 3);
+ _dirtyPalette = true;
+
+ _curFrame = 0;
+ _nextFrameStartTime = 0;
+
+ // Read in the frame offsets. Since we're only worried about the video data
+ // here, we'll calculate video offsets taking into account sound data size
+ stream->seek(0x324 + backSize + 4 * _frameCount);
+
+ _frameOffset = new uint32[_frameCount];
+ for (uint i = 0; i < _frameCount; ++i)
+ _frameOffset[i] = _fileStream->readUint32LE();
+
+ // Adust frame offsets to skip sound data
+ for (uint i = 0; i < _frameCount; ++i)
+ _frameOffset[i] += _fileStream->readUint32LE() & 0xffff;
+}
+
+RL2Decoder::RL2VideoTrack::~RL2VideoTrack() {
+ delete _fileStream;
+ delete[] _palette;
+ delete[] _frameOffset;
+
+ _surface->free();
+ delete _surface;
+ if (_backSurface) {
+ _backSurface->free();
+ delete _backSurface;
+ }
+}
+
+bool RL2Decoder::RL2VideoTrack::endOfTrack() const {
+ return getCurFrame() >= getFrameCount();
+}
+
+bool RL2Decoder::RL2VideoTrack::rewind() {
+ _curFrame = 0;
+ _nextFrameStartTime = 0;
+
+ _fileStream->seek(_frameOffset[0]);
+
+ return true;
+}
+
+uint16 RL2Decoder::RL2VideoTrack::getWidth() const {
+ return _surface->w;
+}
+
+uint16 RL2Decoder::RL2VideoTrack::getHeight() const {
+ return _surface->h;
+}
+
+Graphics::PixelFormat RL2Decoder::RL2VideoTrack::getPixelFormat() const {
+ return _surface->format;
+}
+
+const Graphics::Surface *RL2Decoder::RL2VideoTrack::decodeNextFrame() {
+ if (_curFrame == 0 && _backSurface) {
+ // Read in the background frame
+ _fileStream->seek(0x324);
+ rl2DecodeFrameWithoutBackground(0);
+ _dirtyRects.push_back(Common::Rect(0, 0, _surface->w, _surface->h));
+ }
+
+ _fileStream->seek(_frameOffset[_curFrame]);
+
+ if (_backSurface)
+ rl2DecodeFrameWithBackground();
+ else
+ rl2DecodeFrameWithoutBackground();
+
+ _curFrame++;
+ _nextFrameStartTime += _frameDelay;
+
+ return _surface;
+}
+
+void RL2Decoder::RL2VideoTrack::copyDirtyRectsToBuffer(uint8 *dst, uint pitch) {
+ for (Common::List<Common::Rect>::const_iterator it = _dirtyRects.begin(); it != _dirtyRects.end(); ++it) {
+ for (int y = (*it).top; y < (*it).bottom; ++y) {
+ const int x = (*it).left;
+ memcpy(dst + y * pitch + x, (byte *)_surface->pixels + y * getWidth() + x, (*it).right - x);
+ }
+ }
+
+ clearDirtyRects();
+}
+
+void RL2Decoder::RL2VideoTrack::copyFrame(uint8 *data) {
+ memcpy((byte *)_surface->pixels, data, getWidth() * getHeight());
+
+ // Redraw
+ _dirtyRects.clear();
+ _dirtyRects.push_back(Common::Rect(0, 0, getWidth(), getHeight()));
+}
+
+void RL2Decoder::RL2VideoTrack::rl2DecodeFrameWithoutBackground(int screenOffset) {
+ if (screenOffset == -1)
+ screenOffset = _videoBase;
+ byte *destP = (byte *)_surface->pixels + screenOffset;
+ int frameSize = _surface->w * _surface->h - screenOffset;
+
+ _fileStream->seek(_frameOffset[_curFrame]);
+ while (frameSize > 0) {
+ byte nextByte = _fileStream->readByte();
+
+ if (nextByte < 0x80) {
+ *destP++ = nextByte;
+ --frameSize;
+ } else if (nextByte == 0x80) {
+ int runLength = _fileStream->readByte();
+ if (runLength == 0)
+ return;
+
+ runLength = MIN(runLength, frameSize);
+ Common::fill(destP, destP + runLength, 0);
+ destP += runLength;
+ frameSize -= runLength;
+ } else {
+ int runLength = _fileStream->readByte();
+
+ runLength = MIN(runLength, frameSize);
+ Common::fill(destP, destP + runLength, nextByte & 0x7f);
+ destP += runLength;
+ frameSize -= runLength;
+ }
+ }
+}
+
+void RL2Decoder::RL2VideoTrack::rl2DecodeFrameWithBackground() {
+ int screenOffset = _videoBase;
+ int frameSize = _surface->w * _surface->h - _videoBase;
+ byte *src = (byte *)_backSurface->pixels;
+ byte *dest = (byte *)_surface->pixels;
+
+ _fileStream->seek(_frameOffset[_curFrame]);
+ while (frameSize > 0) {
+ byte nextByte = _fileStream->readByte();
+
+ if (nextByte == 0) {
+ dest[screenOffset] = src[screenOffset];
+ ++screenOffset;
+ --frameSize;
+ } else if (nextByte < 0x80) {
+ dest[screenOffset] = nextByte | 0x80;
+ ++screenOffset;
+ --frameSize;
+ } else if (nextByte == 0x80) {
+ byte runLength = _fileStream->readByte();
+ if (runLength == 0)
+ return;
+
+ assert(runLength <= frameSize);
+ Common::copy(src + screenOffset, src + screenOffset + runLength, dest);
+ screenOffset += runLength;
+ frameSize -= runLength;
+ } else {
+ byte runLength = _fileStream->readByte();
+
+ assert(runLength <= frameSize);
+ Common::fill(dest + screenOffset, dest + screenOffset + runLength, nextByte & 0x7f);
+ screenOffset += runLength;
+ frameSize -= runLength;
+ }
+ }
+}
+
+} // End of namespace Video
diff --git a/engines/voyeur/animation.h b/engines/voyeur/animation.h
new file mode 100644
index 0000000000..dccf409e92
--- /dev/null
+++ b/engines/voyeur/animation.h
@@ -0,0 +1,100 @@
+/* ScummVM - Graphic Adventure Engine
+ *
+ * ScummVM is the legal property of its developers, whose names
+ * are too numerous to list here. Please refer to the COPYRIGHT
+ * file distributed with this source distribution.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ */
+
+#ifndef VOYEUR_ANIMATION_H
+#define VOYEUR_ANIMATION_H
+
+#include "video/video_decoder.h"
+#include "common/list.h"
+#include "common/rect.h"
+#include "common/stream.h"
+
+namespace Video {
+
+/**
+ * Decoder for RL2 videos.
+ *
+ * Video decoder used in engines:
+ * - voyeur
+ */
+class RL2Decoder : public VideoDecoder {
+public:
+ RL2Decoder();
+ virtual ~RL2Decoder();
+
+ bool loadStream(Common::SeekableReadStream *stream);
+
+ const Common::List<Common::Rect> *getDirtyRects() const;
+ void clearDirtyRects();
+ void copyDirtyRectsToBuffer(uint8 *dst, uint pitch);
+
+private:
+ class RL2VideoTrack : public VideoTrack {
+ public:
+ RL2VideoTrack(Common::SeekableReadStream *stream);
+ ~RL2VideoTrack();
+
+ bool endOfTrack() const;
+ bool isRewindable() const { return true; }
+ bool rewind();
+
+ uint16 getWidth() const;
+ uint16 getHeight() const;
+ Graphics::PixelFormat getPixelFormat() const;
+ int getCurFrame() const { return _curFrame; }
+ int getFrameCount() const { return _frameCount; }
+ uint32 getNextFrameStartTime() const { return _nextFrameStartTime; }
+ const Graphics::Surface *decodeNextFrame();
+ const byte *getPalette() const { _dirtyPalette = false; return _palette; }
+ bool hasDirtyPalette() const { return _dirtyPalette; }
+
+ const Common::List<Common::Rect> *getDirtyRects() const { return &_dirtyRects; }
+ void clearDirtyRects() { _dirtyRects.clear(); }
+ void copyDirtyRectsToBuffer(uint8 *dst, uint pitch);
+
+ private:
+ Common::SeekableReadStream *_fileStream;
+ Graphics::Surface *_surface;
+ Graphics::Surface *_backSurface;
+
+ int _curFrame;
+
+ byte *_palette;
+ mutable bool _dirtyPalette;
+
+ uint32 _frameCount;
+ uint32 _videoBase;
+ uint32 *_frameOffset;
+ uint32 _frameDelay;
+ uint32 _nextFrameStartTime;
+
+ Common::List<Common::Rect> _dirtyRects;
+
+ void copyFrame(uint8 *data);
+ void rl2DecodeFrameWithBackground();
+ void rl2DecodeFrameWithoutBackground(int screenOffset = -1);
+ };
+};
+
+} // End of namespace Video
+
+#endif /* VOYEUR_ANIMATION_H */
diff --git a/engines/voyeur/graphics.cpp b/engines/voyeur/graphics.cpp
index 9cf255306f..c79081ceef 100644
--- a/engines/voyeur/graphics.cpp
+++ b/engines/voyeur/graphics.cpp
@@ -604,6 +604,10 @@ void GraphicsManager::clearPalette() {
g_system->getPaletteManager()->setPalette(&palette[0], 0, 256);
}
+void GraphicsManager::setPalette(const byte *palette, int start, int count) {
+ g_system->getPaletteManager()->setPalette(palette, start, count);
+}
+
void GraphicsManager::resetPalette() {
for (int i = 0; i < 256; ++i)
setColor(i, 0, 0, 0);
diff --git a/engines/voyeur/graphics.h b/engines/voyeur/graphics.h
index f6ad837b1a..23a29657f1 100644
--- a/engines/voyeur/graphics.h
+++ b/engines/voyeur/graphics.h
@@ -107,6 +107,7 @@ public:
void sDisplayPic(PictureResource *pic);
void flipPage();
void clearPalette();
+ void setPalette(const byte *palette, int start, int count);
void resetPalette();
void setColor(int idx, byte r, byte g, byte b);
void screenReset();
diff --git a/engines/voyeur/module.mk b/engines/voyeur/module.mk
index 48f63dc2f0..645b62ff49 100644
--- a/engines/voyeur/module.mk
+++ b/engines/voyeur/module.mk
@@ -1,6 +1,7 @@
MODULE := engines/voyeur
MODULE_OBJS := \
+ animation.o \
debugger.o \
detection.o \
events.o \
diff --git a/engines/voyeur/voyeur.cpp b/engines/voyeur/voyeur.cpp
index 8be57e496f..1e140f8621 100644
--- a/engines/voyeur/voyeur.cpp
+++ b/engines/voyeur/voyeur.cpp
@@ -21,6 +21,7 @@
*/
#include "voyeur/voyeur.h"
+#include "voyeur/animation.h"
#include "voyeur/graphics.h"
#include "voyeur/utils.h"
#include "common/scummsys.h"
@@ -156,8 +157,13 @@ void VoyeurEngine::doHeadTitle() {
if (shouldQuit())
return;
- doLock();
+ if (ConfMan.getBool("copy_protection")) {
+ bool result = doLock();
+ if (!result || shouldQuit())
+ return;
+ }
+ playRL2Video("a1100100.rl2");
// TODO
}
@@ -196,6 +202,8 @@ void VoyeurEngine::showConversionScreen() {
_graphicsManager.screenReset();
_bVoy->freeBoltGroup(0x10500);
+
+
}
bool VoyeurEngine::doLock() {
@@ -376,10 +384,35 @@ bool VoyeurEngine::doLock() {
_bVoy->freeBoltGroup(0x10700);
}
+ _eventsManager.mouseOff();
+
delete[] buttonVoc;
delete[] wrongVoc;
return result;
}
+void VoyeurEngine::playRL2Video(const Common::String &filename) {
+ ::Video::RL2Decoder decoder;
+ decoder.loadFile(filename);
+ decoder.start();
+
+ while (!shouldQuit() && !decoder.endOfVideo() && !_voy._incriminate) {
+ if (decoder.hasDirtyPalette()) {
+ const byte *palette = decoder.getPalette();
+ _graphicsManager.setPalette(palette, 0, 256);
+ }
+
+ if (decoder.needsUpdate()) {
+ const Graphics::Surface *frame = decoder.decodeNextFrame();
+
+ Common::copy((byte *)frame->pixels, (byte *)frame->pixels + 320 * 200,
+ (byte *)_graphicsManager._screenSurface.pixels);
+ }
+
+ _eventsManager.pollEvents();
+ g_system->delayMillis(10);
+ }
+}
+
} // End of namespace Voyeur
diff --git a/engines/voyeur/voyeur.h b/engines/voyeur/voyeur.h
index 95a664e7aa..06ac691569 100644
--- a/engines/voyeur/voyeur.h
+++ b/engines/voyeur/voyeur.h
@@ -107,6 +107,8 @@ public:
virtual bool canSaveGameStateCurrently();
virtual Common::Error loadGameState(int slot);
virtual Common::Error saveGameState(int slot, const Common::String &desc);
+
+ void playRL2Video(const Common::String &filename);
};
} // End of namespace Voyeur