aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--engines/configure.engines1
-rw-r--r--engines/engines.mk5
-rw-r--r--engines/plugins_table.h3
-rw-r--r--engines/zvision/detection.cpp249
-rw-r--r--engines/zvision/module.mk18
-rw-r--r--engines/zvision/zork_avi_decoder.cpp136
-rw-r--r--engines/zvision/zork_avi_decoder.h59
-rw-r--r--engines/zvision/zork_raw.cpp186
-rw-r--r--engines/zvision/zork_raw.h67
-rw-r--r--engines/zvision/zvision.cpp217
-rw-r--r--engines/zvision/zvision.h70
11 files changed, 1011 insertions, 0 deletions
diff --git a/engines/configure.engines b/engines/configure.engines
index 963b9f774f..a3525576a2 100644
--- a/engines/configure.engines
+++ b/engines/configure.engines
@@ -52,3 +52,4 @@ add_engine tony "Tony Tough and the Night of Roasted Moths" yes "" "" "16bit"
add_engine tsage "TsAGE" yes
add_engine tucker "Bud Tucker in Double Trouble" yes
add_engine wintermute "Wintermute" no "" "" "png zlib vorbis 16bit"
+add_engine zvision "ZVision" no
diff --git a/engines/engines.mk b/engines/engines.mk
index f58dba0d6d..e399713202 100644
--- a/engines/engines.mk
+++ b/engines/engines.mk
@@ -246,3 +246,8 @@ ifdef ENABLE_WINTERMUTE
DEFINES += -DENABLE_WINTERMUTE=$(ENABLE_WINTERMUTE)
MODULES += engines/wintermute
endif
+
+ifdef ENABLE_ZVISION
+DEFINES += -DENABLE_ZVISION=$(ENABLE_ZVISION)
+MODULES += engines/zvision
+endif \ No newline at end of file
diff --git a/engines/plugins_table.h b/engines/plugins_table.h
index edc94eb0d3..793f15110c 100644
--- a/engines/plugins_table.h
+++ b/engines/plugins_table.h
@@ -119,3 +119,6 @@ LINK_PLUGIN(TUCKER)
#if PLUGIN_ENABLED_STATIC(WINTERMUTE)
LINK_PLUGIN(WINTERMUTE)
#endif
+#if PLUGIN_ENABLED_STATIC(ZVISION)
+LINK_PLUGIN(ZVISION)
+#endif
diff --git a/engines/zvision/detection.cpp b/engines/zvision/detection.cpp
new file mode 100644
index 0000000000..345138b724
--- /dev/null
+++ b/engines/zvision/detection.cpp
@@ -0,0 +1,249 @@
+/* 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 "base/plugins.h"
+
+#include "engines/advancedDetector.h"
+
+#include "common/translation.h"
+#include "common/savefile.h"
+#include "common/str-array.h"
+#include "common/system.h"
+
+#include "zvision/zvision.h"
+
+
+namespace ZVision {
+
+struct ZVisionGameDescription {
+ ADGameDescription desc;
+};
+
+uint32 ZVision::getFeatures() const {
+ return _gameDescription->desc.flags;
+}
+
+Common::Language ZVision::getLanguage() const {
+ return _gameDescription->desc.language;
+}
+
+}
+
+static const PlainGameDescriptor zVisionGames[] = {
+ {"zvision", "ZVision Game"},
+ {"znemesis", "Zork Nemesis: The Forbidden Lands"},
+ {"zgi", "Zork: Grand Inquisitor"},
+ {0, 0}
+};
+
+
+namespace ZVision {
+
+static const ZVisionGameDescription gameDescriptions[] = {
+
+ {
+ // Zork Nemesis English version
+ {
+ "znemesis",
+ 0,
+ AD_ENTRY1s("CSCR.ZFS", "88226e51a205d2e50c67a5237f3bd5f2", 2397741),
+ Common::EN_ANY,
+ Common::kPlatformWindows,
+ ADGF_NO_FLAGS,
+ GUIO1(GUIO_NONE)
+ },
+ },
+
+ { AD_TABLE_END_MARKER }
+};
+
+} // End of namespace ZVision
+
+static const ExtraGuiOption ZVisionExtraGuiOption = {
+ _s("Use original save/load screens"),
+ _s("Use the original save/load screens, instead of the ScummVM ones"),
+ "originalsaveload",
+ false
+};
+
+class ZVisionMetaEngine : public AdvancedMetaEngine {
+public:
+ ZVisionMetaEngine() : AdvancedMetaEngine(ZVision::gameDescriptions, sizeof(ZVision::ZVisionGameDescription), zVisionGames) {
+ _singleid = "zvision";
+ }
+
+ virtual const char *getName() const {
+ return "ZVision";
+ }
+
+ virtual const char *getOriginalCopyright() const {
+ return "ZVision Activision (C) 1996";
+ }
+
+ virtual bool hasFeature(MetaEngineFeature f) const;
+ virtual bool createInstance(OSystem *syst, Engine **engine, const ADGameDescription *desc) const;
+ virtual const ExtraGuiOptions getExtraGuiOptions(const Common::String &target) const;
+ SaveStateList listSaves(const char *target) const;
+ virtual int getMaximumSaveSlot() const;
+ void removeSaveState(const char *target, int slot) const;
+ SaveStateDescriptor querySaveMetaInfos(const char *target, int slot) const;
+};
+
+bool ZVisionMetaEngine::hasFeature(MetaEngineFeature f) const {
+ return false;
+ /*
+ (f == kSupportsListSaves) ||
+ (f == kSupportsLoadingDuringStartup) ||
+ (f == kSupportsDeleteSave) ||
+ (f == kSavesSupportMetaInfo) ||
+ (f == kSavesSupportThumbnail) ||
+ (f == kSavesSupportCreationDate) ||
+ (f == kSavesSupportPlayTime);
+ */
+}
+
+/*bool ZVision::ZVision::hasFeature(EngineFeature f) const {
+ return
+ (f == kSupportsRTL) ||
+ (f == kSupportsLoadingDuringRuntime) ||
+ (f == kSupportsSavingDuringRuntime);
+}*/
+
+bool ZVisionMetaEngine::createInstance(OSystem *syst, Engine **engine, const ADGameDescription *desc) const {
+ const ZVision::ZVisionGameDescription *gd = (const ZVision::ZVisionGameDescription *)desc;
+ if (gd) {
+ *engine = new ZVision::ZVision(syst, gd);
+ }
+ return gd != 0;
+}
+
+const ExtraGuiOptions ZVisionMetaEngine::getExtraGuiOptions(const Common::String &target) const {
+ ExtraGuiOptions options;
+ options.push_back(ZVisionExtraGuiOption);
+ return options;
+}
+
+SaveStateList ZVisionMetaEngine::listSaves(const char *target) const {
+ //Common::SaveFileManager *saveFileMan = g_system->getSavefileManager();
+ /*ZVision::ZVision::SaveHeader header;
+ Common::String pattern = target;
+ pattern += ".???";
+
+ Common::StringArray filenames;
+ filenames = saveFileMan->listSavefiles(pattern.c_str());
+ Common::sort(filenames.begin(), filenames.end()); // Sort (hopefully ensuring we are sorted numerically..)*/
+
+ SaveStateList saveList;
+/* for (Common::StringArray::const_iterator file = filenames.begin(); file != filenames.end(); file++) {
+ // Obtain the last 3 digits of the filename, since they correspond to the save slot
+ int slotNum = atoi(file->c_str() + file->size() - 3);
+
+ if (slotNum >= 0 && slotNum <= 999) {
+ Common::InSaveFile *in = saveFileMan->openForLoading(file->c_str());
+ if (in) {
+ if (ZVision::ZVision::readSaveHeader(in, false, header) == ZVision::ZVision::kRSHENoError) {
+ saveList.push_back(SaveStateDescriptor(slotNum, header.description));
+ }
+ delete in;
+ }
+ }
+ }*/
+
+ return saveList;
+}
+
+int ZVisionMetaEngine::getMaximumSaveSlot() const {
+ return 999;
+}
+
+void ZVisionMetaEngine::removeSaveState(const char *target, int slot) const {
+ /*
+ Common::SaveFileManager *saveFileMan = g_system->getSavefileManager();
+ Common::String filename = ZVision::ZVision::getSavegameFilename(target, slot);
+
+ saveFileMan->removeSavefile(filename.c_str());
+
+ Common::StringArray filenames;
+ Common::String pattern = target;
+ pattern += ".???";
+ filenames = saveFileMan->listSavefiles(pattern.c_str());
+ Common::sort(filenames.begin(), filenames.end()); // Sort (hopefully ensuring we are sorted numerically..)
+
+ for (Common::StringArray::const_iterator file = filenames.begin(); file != filenames.end(); ++file) {
+ // Obtain the last 3 digits of the filename, since they correspond to the save slot
+ int slotNum = atoi(file->c_str() + file->size() - 3);
+
+ // Rename every slot greater than the deleted slot,
+ if (slotNum > slot) {
+ saveFileMan->renameSavefile(file->c_str(), filename.c_str());
+ filename = ZVision::ZVision::getSavegameFilename(target, ++slot);
+ }
+ }
+ */
+}
+
+SaveStateDescriptor ZVisionMetaEngine::querySaveMetaInfos(const char *target, int slot) const {
+ /*
+ Common::String filename = ZVision::ZVision::getSavegameFilename(target, slot);
+ Common::InSaveFile *in = g_system->getSavefileManager()->openForLoading(filename.c_str());
+
+ if (in) {
+ ZVision::ZVision::SaveHeader header;
+ ZVision::ZVision::kReadSaveHeaderError error;
+
+ error = ZVision::ZVision::readSaveHeader(in, true, header);
+ delete in;
+
+ if (error == ZVision::ZVision::kRSHENoError) {
+ SaveStateDescriptor desc(slot, header.description);
+
+ desc.setThumbnail(header.thumbnail);
+
+ if (header.version > 0) {
+ int day = (header.saveDate >> 24) & 0xFF;
+ int month = (header.saveDate >> 16) & 0xFF;
+ int year = header.saveDate & 0xFFFF;
+
+ desc.setSaveDate(year, month, day);
+
+ int hour = (header.saveTime >> 16) & 0xFF;
+ int minutes = (header.saveTime >> 8) & 0xFF;
+
+ desc.setSaveTime(hour, minutes);
+
+ desc.setPlayTime(header.playTime * 1000);
+ }
+
+ return desc;
+ }
+ }
+ */
+
+ return SaveStateDescriptor();
+}
+
+#if PLUGIN_ENABLED_DYNAMIC(ZVISION)
+ REGISTER_PLUGIN_DYNAMIC(ZVISION, PLUGIN_TYPE_ENGINE, ZVisionMetaEngine);
+#else
+ REGISTER_PLUGIN_STATIC(ZVISION, PLUGIN_TYPE_ENGINE, ZVisionMetaEngine);
+#endif
diff --git a/engines/zvision/module.mk b/engines/zvision/module.mk
new file mode 100644
index 0000000000..854ee0307c
--- /dev/null
+++ b/engines/zvision/module.mk
@@ -0,0 +1,18 @@
+MODULE := engines/zvision
+
+MODULE_OBJS := \
+ detection.o \
+ zvision.o \
+ zork_avi_decoder.o \
+ zork_raw.o
+
+MODULE_DIRS += \
+ engines/zvision
+
+# This module can be built as a plugin
+ifeq ($(ENABLE_ZVISION), DYNAMIC_PLUGIN)
+PLUGIN := 1
+endif
+
+# Include common rules
+include $(srcdir)/rules.mk \ No newline at end of file
diff --git a/engines/zvision/zork_avi_decoder.cpp b/engines/zvision/zork_avi_decoder.cpp
new file mode 100644
index 0000000000..9bcc163721
--- /dev/null
+++ b/engines/zvision/zork_avi_decoder.cpp
@@ -0,0 +1,136 @@
+/* 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 "common/stream.h"
+#include "audio/audiostream.h"
+
+#include "engines/zvision/zork_avi_decoder.h"
+#include "engines/zvision/zork_raw.h"
+
+namespace ZVision {
+
+// Redefinitions from avi_decoder.cpp
+#define ID_VIDS MKTAG('v','i','d','s')
+#define ID_TXTS MKTAG('t','x','t','s')
+#define ID_STRF MKTAG('s','t','r','f')
+#define ID_AUDS MKTAG('a','u','d','s')
+#define ID_MIDS MKTAG('m','i','d','s')
+
+// Copied off AVIDecoder::handleStreamHeader()
+void ZorkAVIDecoder::handleStreamHeader() {
+ AVIStreamHeader sHeader;
+ sHeader.size = _fileStream->readUint32LE();
+ sHeader.streamType = _fileStream->readUint32BE();
+
+ if (sHeader.streamType == ID_MIDS || sHeader.streamType == ID_TXTS)
+ error("Unhandled MIDI/Text stream");
+
+ sHeader.streamHandler = _fileStream->readUint32BE();
+ sHeader.flags = _fileStream->readUint32LE();
+ sHeader.priority = _fileStream->readUint16LE();
+ sHeader.language = _fileStream->readUint16LE();
+ sHeader.initialFrames = _fileStream->readUint32LE();
+ sHeader.scale = _fileStream->readUint32LE();
+ sHeader.rate = _fileStream->readUint32LE();
+ sHeader.start = _fileStream->readUint32LE();
+ sHeader.length = _fileStream->readUint32LE();
+ sHeader.bufferSize = _fileStream->readUint32LE();
+ sHeader.quality = _fileStream->readUint32LE();
+ sHeader.sampleSize = _fileStream->readUint32LE();
+
+ _fileStream->skip(sHeader.size - 48); // Skip over the remainder of the chunk (frame)
+
+ if (_fileStream->readUint32BE() != ID_STRF)
+ error("Could not find STRF tag");
+
+ uint32 strfSize = _fileStream->readUint32LE();
+ uint32 startPos = _fileStream->pos();
+
+ if (sHeader.streamType == ID_VIDS) {
+ BitmapInfoHeader bmInfo;
+ bmInfo.size = _fileStream->readUint32LE();
+ bmInfo.width = _fileStream->readUint32LE();
+ bmInfo.height = _fileStream->readUint32LE();
+ bmInfo.planes = _fileStream->readUint16LE();
+ bmInfo.bitCount = _fileStream->readUint16LE();
+ bmInfo.compression = _fileStream->readUint32BE();
+ bmInfo.sizeImage = _fileStream->readUint32LE();
+ bmInfo.xPelsPerMeter = _fileStream->readUint32LE();
+ bmInfo.yPelsPerMeter = _fileStream->readUint32LE();
+ bmInfo.clrUsed = _fileStream->readUint32LE();
+ bmInfo.clrImportant = _fileStream->readUint32LE();
+
+ if (bmInfo.clrUsed == 0)
+ bmInfo.clrUsed = 256;
+
+ if (sHeader.streamHandler == 0)
+ sHeader.streamHandler = bmInfo.compression;
+
+ AVIVideoTrack *track = new AVIVideoTrack(_header.totalFrames, sHeader, bmInfo);
+
+ if (bmInfo.bitCount == 8) {
+ byte *palette = const_cast<byte *>(track->getPalette());
+ for (uint32 i = 0; i < bmInfo.clrUsed; i++) {
+ palette[i * 3 + 2] = _fileStream->readByte();
+ palette[i * 3 + 1] = _fileStream->readByte();
+ palette[i * 3] = _fileStream->readByte();
+ _fileStream->readByte();
+ }
+
+ track->markPaletteDirty();
+ }
+
+ addTrack(track);
+ } else if (sHeader.streamType == ID_AUDS) {
+ PCMWaveFormat wvInfo;
+ wvInfo.tag = _fileStream->readUint16LE();
+ wvInfo.channels = _fileStream->readUint16LE();
+ wvInfo.samplesPerSec = _fileStream->readUint32LE();
+ wvInfo.avgBytesPerSec = _fileStream->readUint32LE();
+ wvInfo.blockAlign = _fileStream->readUint16LE();
+ wvInfo.size = _fileStream->readUint16LE();
+
+ // AVI seems to treat the sampleSize as including the second
+ // channel as well, so divide for our sake.
+ if (wvInfo.channels == 2)
+ sHeader.sampleSize /= 2;
+
+ addTrack(new ZorkAVIAudioTrack(sHeader, wvInfo, _soundType));
+ }
+
+ // Ensure that we're at the end of the chunk
+ _fileStream->seek(startPos + strfSize);
+}
+
+void ZorkAVIDecoder::ZorkAVIAudioTrack::queueSound(Common::SeekableReadStream *stream) {
+ if (_audStream) {
+ if (_wvInfo.tag == kWaveFormatZorkPCM) {
+ assert(_wvInfo.size == 8);
+ _audStream->queueAudioStream(makeRawZorkStream(stream, _wvInfo.samplesPerSec, DisposeAfterUse::YES), DisposeAfterUse::YES);
+ }
+ } else {
+ delete stream;
+ }
+}
+
+} // End of namespace ZVision
diff --git a/engines/zvision/zork_avi_decoder.h b/engines/zvision/zork_avi_decoder.h
new file mode 100644
index 0000000000..f6b2ca7977
--- /dev/null
+++ b/engines/zvision/zork_avi_decoder.h
@@ -0,0 +1,59 @@
+/* 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 ZORK_AVI_DECODER_H
+#define ZORK_AVI_DECODER_H
+
+#include "video/avi_decoder.h"
+
+namespace ZVision {
+
+class ZorkAVIDecoder : public Video::AVIDecoder {
+public:
+ ZorkAVIDecoder(Audio::Mixer::SoundType soundType = Audio::Mixer::kPlainSoundType) :
+ Video::AVIDecoder(soundType) {}
+
+ virtual ~ZorkAVIDecoder() {}
+
+private:
+ class ZorkAVIAudioTrack : public Video::AVIDecoder::AVIAudioTrack {
+ public:
+ ZorkAVIAudioTrack(const AVIStreamHeader &streamHeader, const PCMWaveFormat &waveFormat, Audio::Mixer::SoundType soundType) :
+ Video::AVIDecoder::AVIAudioTrack(streamHeader, waveFormat, soundType) {}
+ virtual ~ZorkAVIAudioTrack() {}
+
+ void queueSound(Common::SeekableReadStream *stream);
+ };
+
+ void handleStreamHeader();
+
+ private:
+ // Audio Codecs
+ enum {
+ kWaveFormatZorkPCM = 17 // special Zork PCM audio format (clashes with MS IMA ADPCM)
+ };
+};
+
+} // End of namespace ZVision
+
+#endif
diff --git a/engines/zvision/zork_raw.cpp b/engines/zvision/zork_raw.cpp
new file mode 100644
index 0000000000..9332aeb52e
--- /dev/null
+++ b/engines/zvision/zork_raw.cpp
@@ -0,0 +1,186 @@
+/* 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 "common/endian.h"
+#include "common/memstream.h"
+#include "common/textconsole.h"
+#include "common/util.h"
+
+#include "audio/audiostream.h"
+
+#include "engines/zvision/zork_raw.h"
+
+namespace ZVision {
+
+#pragma mark -
+#pragma mark --- RawZorkStream ---
+#pragma mark -
+
+/**
+ * This is a stream, which allows for playing raw PCM data from a stream.
+ */
+class RawZorkStream : public Audio::SeekableAudioStream {
+public:
+ RawZorkStream(int rate, DisposeAfterUse::Flag disposeStream, Common::SeekableReadStream *stream)
+ : _rate(rate), _playtime(0, rate), _stream(stream, disposeStream), _endOfData(false), _buffer(0) {
+ // Setup our buffer for readBuffer
+ _buffer = new byte[kSampleBufferLength];
+ assert(_buffer);
+
+ // Calculate the total playtime of the stream
+ _playtime = Audio::Timestamp(0, _stream->size() / 2 / 1, rate);
+ }
+
+ ~RawZorkStream() {
+ delete[] _buffer;
+ }
+
+ int readBuffer(int16 *buffer, const int numSamples);
+
+ bool isStereo() const { return true; }
+ bool endOfData() const { return _endOfData; }
+
+ int getRate() const { return _rate; }
+ Audio::Timestamp getLength() const { return _playtime; }
+
+ bool seek(const Audio::Timestamp &where);
+private:
+ const int _rate; ///< Sample rate of stream
+ Audio::Timestamp _playtime; ///< Calculated total play time
+ Common::DisposablePtr<Common::SeekableReadStream> _stream; ///< Stream to read data from
+ bool _endOfData; ///< Whether the stream end has been reached
+
+ byte *_buffer; ///< Buffer used in readBuffer
+ enum {
+ /**
+ * How many samples we can buffer at once.
+ *
+ * TODO: Check whether this size suffices
+ * for systems with slow disk I/O.
+ */
+ kSampleBufferLength = 2048
+ };
+
+ /**
+ * Fill the temporary sample buffer used in readBuffer.
+ *
+ * @param maxSamples Maximum samples to read.
+ * @return actual count of samples read.
+ */
+ int fillBuffer(int maxSamples);
+};
+
+int RawZorkStream::readBuffer(int16 *buffer, const int numSamples) {
+ int samplesLeft = numSamples;
+
+ while (samplesLeft > 0) {
+ // Try to read up to "samplesLeft" samples.
+ int len = fillBuffer(samplesLeft);
+
+ // In case we were not able to read any samples
+ // we will stop reading here.
+ if (!len)
+ break;
+
+ // Adjust the samples left to read.
+ samplesLeft -= len;
+
+ // Copy the data to the caller's buffer.
+ const byte *src = _buffer;
+ while (len-- > 0) {
+ if (*src < 128)
+ *buffer++ = ((128 - *src) << 8) ^ 0x8000;
+ else
+ *buffer++ = (*src << 8) ^ 0x8000;
+ src++;
+ }
+ }
+
+ return numSamples - samplesLeft;
+}
+
+int RawZorkStream::fillBuffer(int maxSamples) {
+ int bufferedSamples = 0;
+ byte *dst = _buffer;
+
+ // We can only read up to "kSampleBufferLength" samples
+ // so we take this into consideration, when trying to
+ // read up to maxSamples.
+ maxSamples = MIN<int>(kSampleBufferLength, maxSamples);
+
+ // We will only read up to maxSamples
+ while (maxSamples > 0 && !endOfData()) {
+ // Try to read all the sample data and update the
+ // destination pointer.
+ const int bytesRead = _stream->read(dst, maxSamples);
+ dst += bytesRead;
+
+ // Calculate how many samples we actually read.
+ const int samplesRead = bytesRead;
+
+ // Update all status variables
+ bufferedSamples += samplesRead;
+ maxSamples -= samplesRead;
+
+ // We stop stream playback, when we reached the end of the data stream.
+ // We also stop playback when an error occures.
+ if (_stream->pos() == _stream->size() || _stream->err() || _stream->eos())
+ _endOfData = true;
+ }
+
+ return bufferedSamples;
+}
+
+bool RawZorkStream::seek(const Audio::Timestamp &where) {
+ _endOfData = true;
+
+ if (where > _playtime)
+ return false;
+
+ const uint32 seekSample = convertTimeToStreamPos(where, getRate(), isStereo()).totalNumberOfFrames();
+ _stream->seek(seekSample, SEEK_SET);
+
+ // In case of an error we will not continue stream playback.
+ if (!_stream->err() && !_stream->eos() && _stream->pos() != _stream->size())
+ _endOfData = false;
+
+ return true;
+}
+
+#pragma mark -
+#pragma mark --- Raw stream factories ---
+#pragma mark -
+
+Audio::SeekableAudioStream *makeRawZorkStream(Common::SeekableReadStream *stream,
+ int rate,
+ DisposeAfterUse::Flag disposeAfterUse) {
+ assert(stream->size() % 2 == 0);
+ return new RawZorkStream(rate, disposeAfterUse, stream);
+}
+
+Audio::SeekableAudioStream *makeRawZorkStream(const byte *buffer, uint32 size,
+ int rate,
+ DisposeAfterUse::Flag disposeAfterUse) {
+ return makeRawZorkStream(new Common::MemoryReadStream(buffer, size, disposeAfterUse), rate, DisposeAfterUse::YES);
+}
+
+} // End of namespace Audio
diff --git a/engines/zvision/zork_raw.h b/engines/zvision/zork_raw.h
new file mode 100644
index 0000000000..a8f8ce037f
--- /dev/null
+++ b/engines/zvision/zork_raw.h
@@ -0,0 +1,67 @@
+/* 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 ZVISION_ZORK_RAW_H
+#define ZVISION_ZORK_RAW_H
+
+#include "common/scummsys.h"
+#include "common/types.h"
+
+#include "common/list.h"
+
+
+namespace Common {
+class SeekableReadStream;
+}
+
+namespace ZVision {
+
+class SeekableAudioStream;
+
+/**
+ * Creates an audio stream, which plays from the given buffer.
+ *
+ * @param buffer Buffer to play from.
+ * @param size Size of the buffer in bytes.
+ * @param rate Rate of the sound data.
+ * @param disposeAfterUse Whether to free the buffer after use (with free!).
+ * @return The new SeekableAudioStream (or 0 on failure).
+ */
+Audio::SeekableAudioStream *makeRawZorkStream(const byte *buffer, uint32 size,
+ int rate,
+ DisposeAfterUse::Flag disposeAfterUse = DisposeAfterUse::YES);
+
+/**
+ * Creates an audio stream, which plays from the given stream.
+ *
+ * @param stream Stream object to play from.
+ * @param rate Rate of the sound data.
+ * @param disposeAfterUse Whether to delete the stream after use.
+ * @return The new SeekableAudioStream (or 0 on failure).
+ */
+Audio::SeekableAudioStream *makeRawZorkStream(Common::SeekableReadStream *stream,
+ int rate,
+ DisposeAfterUse::Flag disposeAfterUse = DisposeAfterUse::YES);
+
+} // End of namespace Audio
+
+#endif
diff --git a/engines/zvision/zvision.cpp b/engines/zvision/zvision.cpp
new file mode 100644
index 0000000000..0e553e6287
--- /dev/null
+++ b/engines/zvision/zvision.cpp
@@ -0,0 +1,217 @@
+#include "common/scummsys.h"
+
+#include "common/config-manager.h"
+#include "common/debug.h"
+#include "common/debug-channels.h"
+#include "common/error.h"
+#include "common/EventRecorder.h"
+#include "common/file.h"
+#include "common/fs.h"
+
+#include "audio/audiostream.h"
+#include "audio/mixer.h"
+
+#include "graphics/palette.h"
+#include "graphics/surface.h"
+#include "graphics/decoders/tga.h"
+
+#include "video/video_decoder.h"
+#include "video/avi_decoder.h"
+
+#include "engines/util.h"
+
+#include "zvision/zvision.h"
+#include "zvision/zork_avi_decoder.h"
+#include "zvision/zork_raw.h"
+
+namespace ZVision {
+
+ZVision::ZVision(OSystem *syst, const ZVisionGameDescription *gameDesc) : Engine(syst), _gameDescription(gameDesc) {
+ // Put your engine in a sane state, but do nothing big yet;
+ // in particular, do not load data from files; rather, if you
+ // need to do such things, do them from run().
+
+ // Do not initialize graphics here
+
+ // However this is the place to specify all default directories
+ const Common::FSNode gameDataDir(ConfMan.get("path"));
+ SearchMan.addSubDirectoryMatching(gameDataDir, "zassets");
+ SearchMan.addSubDirectoryMatching(gameDataDir, "zassets/asylum");
+ SearchMan.addSubDirectoryMatching(gameDataDir, "zassets/castle");
+ SearchMan.addSubDirectoryMatching(gameDataDir, "zassets/conserv");
+ SearchMan.addSubDirectoryMatching(gameDataDir, "zassets/endgame");
+ SearchMan.addSubDirectoryMatching(gameDataDir, "zassets/global");
+ SearchMan.addSubDirectoryMatching(gameDataDir, "zassets/global/venus");
+ SearchMan.addSubDirectoryMatching(gameDataDir, "zassets/global2");
+ SearchMan.addSubDirectoryMatching(gameDataDir, "zassets/global3");
+ SearchMan.addSubDirectoryMatching(gameDataDir, "zassets/monast");
+ SearchMan.addSubDirectoryMatching(gameDataDir, "zassets/temple");
+
+ // Here is the right place to set up the engine specific debug channels
+ //DebugMan.addDebugChannel(kZVisionDebugExample, "example", "this is just an example for a engine specific debug channel");
+ //DebugMan.addDebugChannel(kZVisionDebugExample2, "example2", "also an example");
+
+ // Don't forget to register your random source
+ _rnd = new Common::RandomSource("zvision");
+
+ debug("ZVision::ZVision");
+}
+
+ZVision::~ZVision() {
+ debug("ZVision::~ZVision");
+
+ // Dispose your resources here
+ delete _rnd;
+
+ // Remove all of our debug levels here
+ DebugMan.clearAllDebugChannels();
+}
+
+void playVideo(Video::VideoDecoder *videoDecoder /*, VideoState videoState*/) {
+ if (!videoDecoder)
+ return;
+
+ videoDecoder->start();
+
+ byte *scaleBuffer = 0;
+ byte bytesPerPixel = videoDecoder->getPixelFormat().bytesPerPixel;
+ uint16 width = videoDecoder->getWidth();
+ uint16 height = videoDecoder->getHeight();
+ uint16 pitch = videoDecoder->getWidth() * bytesPerPixel;
+ uint16 screenWidth = 640;//g_sci->_gfxScreen->getDisplayWidth();
+ uint16 screenHeight = 480;//g_sci->_gfxScreen->getDisplayHeight();
+
+ //videoState.fileName.toLowercase();
+
+ /*if (screenWidth == 640 && width <= 320 && height <= 240 && ((videoState.flags & kDoubled))) {
+ width *= 2;
+ height *= 2;
+ pitch *= 2;
+ scaleBuffer = new byte[width * height * bytesPerPixel];
+ }*/
+
+ uint16 x, y;
+
+ // Sanity check...
+ /*if (videoState.x > 0 && videoState.y > 0 && isVMD) {
+ x = videoState.x;
+ y = videoState.y;
+
+ if (x + width > screenWidth || y + height > screenHeight) {
+ // Happens in the Lighthouse demo
+ warning("VMD video won't fit on screen, centering it instead");
+ x = (screenWidth - width) / 2;
+ y = (screenHeight - height) / 2;
+ }
+ } else {*/
+ x = (screenWidth - width) / 2;
+ y = (screenHeight - height) / 2;
+ //}
+
+ bool skipVideo = false;
+
+ while (!g_engine->shouldQuit() && !videoDecoder->endOfVideo() && !skipVideo) {
+ if (videoDecoder->needsUpdate()) {
+ const Graphics::Surface *frame = videoDecoder->decodeNextFrame();
+
+ if (frame) {
+ if (scaleBuffer) {
+ // TODO: Perhaps reuse the relevant function from SCI?
+ //g_sci->_gfxScreen->scale2x((byte *)frame->pixels, scaleBuffer, videoDecoder->getWidth(), videoDecoder->getHeight(), bytesPerPixel);
+ g_system->copyRectToScreen(scaleBuffer, pitch, x, y, width, height);
+ } else {
+ g_system->copyRectToScreen(frame->pixels, frame->pitch, x, y, width, height);
+ }
+
+ g_system->updateScreen();
+ }
+ }
+
+ Common::Event event;
+ while (g_system->getEventManager()->pollEvent(event)) {
+ if ((event.type == Common::EVENT_KEYDOWN && event.kbd.keycode == Common::KEYCODE_ESCAPE) || event.type == Common::EVENT_LBUTTONUP)
+ skipVideo = true;
+ }
+
+ g_system->delayMillis(10);
+ }
+
+ delete[] scaleBuffer;
+ delete videoDecoder;
+}
+
+Common::Error ZVision::run() {
+ //Graphics::PixelFormat format = Graphics::PixelFormat(4, 8, 8, 8, 8, 16, 8, 0, 24); // ARGB8888
+ Graphics::PixelFormat format = Graphics::PixelFormat(2, 5, 5, 5, 0, 10, 5, 0, 0); // RGB555
+ initGraphics(640, 480, true, &format);
+
+ // Create debugger console. It requires GFX to be initialized
+ _console = new Console(this);
+
+ // Additional setup.
+ debug("ZVision::init");
+
+ // Your main even loop should be (invoked from) here.
+ debug("ZVision::go: Hello, World!");
+
+ // This test will show up if -d1 and --debugflags=example are specified on the commandline
+ //debugC(1, kZVisionDebugExample, "Example debug call");
+
+ // This test will show up if --debugflags=example or --debugflags=example2 or both of them and -d3 are specified on the commandline
+ //debugC(3, kZVisionDebugExample | kZVisionDebugExample2, "Example debug call two");
+
+#if 1
+ // Video test
+ Video::VideoDecoder *videoDecoder = new ZorkAVIDecoder();
+ if (videoDecoder && videoDecoder->loadFile(/*"TD9EAZ1C.AVI"*/"T000A11C.AVI")) {
+ Common::List<Graphics::PixelFormat> formats;
+ formats.push_back(videoDecoder->getPixelFormat());
+ initGraphics(640, 480, true, formats);
+
+ playVideo(videoDecoder);
+ }
+#endif
+
+ Common::File f;
+
+#if 1
+ // Image test
+ f.open("CB8EB11C.TGA");
+
+ Graphics::TGADecoder tga;
+ if (!tga.loadStream(f))
+ error("Error while reading TGA image");
+ f.close();
+
+ const Graphics::Surface *tgaSurface = tga.getSurface();
+
+ Graphics::Surface *screen = g_system->lockScreen();
+ for (uint16 y = 0; y < tgaSurface->h; y++)
+ memcpy(screen->getBasePtr(0, y), tgaSurface->getBasePtr(0, y), tgaSurface->pitch);
+ g_system->unlockScreen();
+
+ tga.destroy();
+#endif
+
+#if 1
+ // Sound test
+ f.open("C000H9TC.RAW");
+ Audio::SeekableAudioStream *audioStream = makeRawZorkStream(&f, 22050, DisposeAfterUse::YES);
+ Audio::SoundHandle handle;
+ g_system->getMixer()->playStream(Audio::Mixer::kSFXSoundType, &handle, audioStream);
+#endif
+
+ // Main loop
+ Common::EventManager *eventMan = g_system->getEventManager();
+ Common::Event event;
+
+ while (!shouldQuit()) {
+ eventMan->pollEvent(event); // eat events
+ g_system->updateScreen();
+ g_system->delayMillis(10);
+ }
+
+ return Common::kNoError;
+}
+
+} // End of namespace ZVision
diff --git a/engines/zvision/zvision.h b/engines/zvision/zvision.h
new file mode 100644
index 0000000000..c2a42f1e21
--- /dev/null
+++ b/engines/zvision/zvision.h
@@ -0,0 +1,70 @@
+/* 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 ZVISION_H
+#define ZVISION_H
+
+#include "common/random.h"
+#include "engines/engine.h"
+#include "gui/debugger.h"
+
+namespace ZVision {
+
+struct ZVisionGameDescription;
+class Console;
+
+// our engine debug channels
+enum {
+ kZDebugExample = 1 << 0,
+ kZDebugExample2 = 1 << 1
+ // next new channel must be 1 << 2 (4)
+ // the current limitation is 32 debug channels (1 << 31 is the last one)
+};
+
+class ZVision : public Engine {
+public:
+ ZVision(OSystem *syst, const ZVisionGameDescription *gameDesc);
+ ~ZVision();
+
+ uint32 getFeatures() const;
+ Common::Language getLanguage() const;
+ virtual Common::Error run();
+
+private:
+ Console *_console;
+ const ZVisionGameDescription *_gameDescription;
+
+ // We need random numbers
+ Common::RandomSource *_rnd;
+};
+
+// Example console class
+class Console : public GUI::Debugger {
+public:
+ Console(ZVision *vm) {}
+ virtual ~Console(void) {}
+};
+
+} // End of namespace ZVision
+
+#endif