From d0b341e6ca7010641c362bb36ebfc3d225955056 Mon Sep 17 00:00:00 2001 From: richiesams Date: Tue, 4 Jun 2013 14:17:19 -0500 Subject: ZVISION: Create zvision bare structure Add zvision base engine to engines/zvision as well as modify the necessary engine files (configure.engines, etc.) in order for it to be recognized. --- engines/configure.engines | 1 + engines/engines.mk | 5 + engines/plugins_table.h | 3 + engines/zvision/detection.cpp | 249 +++++++++++++++++++++++++++++++++++ engines/zvision/module.mk | 18 +++ engines/zvision/zork_avi_decoder.cpp | 136 +++++++++++++++++++ engines/zvision/zork_avi_decoder.h | 59 +++++++++ engines/zvision/zork_raw.cpp | 186 ++++++++++++++++++++++++++ engines/zvision/zork_raw.h | 67 ++++++++++ engines/zvision/zvision.cpp | 217 ++++++++++++++++++++++++++++++ engines/zvision/zvision.h | 70 ++++++++++ 11 files changed, 1011 insertions(+) create mode 100644 engines/zvision/detection.cpp create mode 100644 engines/zvision/module.mk create mode 100644 engines/zvision/zork_avi_decoder.cpp create mode 100644 engines/zvision/zork_avi_decoder.h create mode 100644 engines/zvision/zork_raw.cpp create mode 100644 engines/zvision/zork_raw.h create mode 100644 engines/zvision/zvision.cpp create mode 100644 engines/zvision/zvision.h 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(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 _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(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 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 -- cgit v1.2.3