From 0e46c809d10dcd8fd766d7adcb966785e7955f5b Mon Sep 17 00:00:00 2001 From: Paul Gilbert Date: Tue, 18 Feb 2014 20:08:58 -0500 Subject: MADS: Initial implementation of MSurface class and dependant classes --- engines/mads/compression.cpp | 185 ++++++++++++ engines/mads/compression.h | 80 +++++ engines/mads/detection.cpp | 19 +- engines/mads/events.cpp | 34 +++ engines/mads/events.h | 43 +++ engines/mads/mads.cpp | 42 ++- engines/mads/mads.h | 34 ++- engines/mads/module.mk | 9 +- engines/mads/msprite.cpp | 207 +++++++++++++ engines/mads/msprite.h | 152 ++++++++++ engines/mads/msurface.cpp | 690 +++++++++++++++++++++++++++++++++++++++++++ engines/mads/msurface.h | 185 ++++++++++++ engines/mads/palette.cpp | 289 ++++++++++++++++++ engines/mads/palette.h | 110 +++++++ engines/mads/resources.cpp | 32 ++ engines/mads/resources.h | 57 ++++ engines/mads/sound.cpp | 9 +- engines/mads/sound.h | 3 +- engines/mads/sound_nebular.h | 4 +- 19 files changed, 2153 insertions(+), 31 deletions(-) create mode 100644 engines/mads/compression.cpp create mode 100644 engines/mads/compression.h create mode 100644 engines/mads/events.cpp create mode 100644 engines/mads/events.h create mode 100644 engines/mads/msprite.cpp create mode 100644 engines/mads/msprite.h create mode 100644 engines/mads/msurface.cpp create mode 100644 engines/mads/msurface.h create mode 100644 engines/mads/palette.cpp create mode 100644 engines/mads/palette.h create mode 100644 engines/mads/resources.cpp create mode 100644 engines/mads/resources.h diff --git a/engines/mads/compression.cpp b/engines/mads/compression.cpp new file mode 100644 index 0000000000..f8df5a5e43 --- /dev/null +++ b/engines/mads/compression.cpp @@ -0,0 +1,185 @@ +/* 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 "mads/compression.h" + +namespace MADS { + +const char *const madsPackString = "MADSPACK"; + +bool MadsPack::isCompressed(Common::SeekableReadStream *stream) { + // Check whether the passed stream is packed + + char tempBuffer[8]; + stream->seek(0); + if (stream->read(tempBuffer, 8) == 8) { + if (!strncmp(tempBuffer, madsPackString, 8)) + return true; + } + + return false; +} + +MadsPack::MadsPack(Common::SeekableReadStream *stream) { + initialise(stream); +} + +MadsPack::MadsPack(const Common::String &resourceName, MADSEngine *vm) { + Common::SeekableReadStream *stream = vm->_resources->get(resourceName); + initialise(stream); + vm->_resources->toss(resourceName); +} + +void MadsPack::initialise(Common::SeekableReadStream *stream) { + if (!MadsPack::isCompressed(stream)) + error("Attempted to decompress a resource that was not MadsPacked"); + + stream->seek(14); + _count = stream->readUint16LE(); + _items = new MadsPackEntry[_count]; + + byte *headerData = new byte[0xA0]; + byte *header = headerData; + stream->read(headerData, 0xA0); + + for (int i = 0; i < _count; ++i, header += 10) { + // Get header data + _items[i].hash = READ_LE_UINT16(header); + _items[i].size = READ_LE_UINT32(header + 2); + _items[i].compressedSize = READ_LE_UINT32(header + 6); + + _items[i].data = new byte[_items[i].size]; + if (_items[i].size == _items[i].compressedSize) { + // Entry isn't compressed + stream->read(_items[i].data, _items[i].size); + } else { + // Decompress the entry + byte *compressedData = new byte[_items[i].compressedSize]; + stream->read(compressedData, _items[i].compressedSize); + + FabDecompressor fab; + fab.decompress(compressedData, _items[i].compressedSize, _items[i].data, _items[i].size); + delete[] compressedData; + } + } + + delete[] headerData; + _dataOffset = stream->pos(); +} + +MadsPack::~MadsPack() { + for (int i = 0; i < _count; ++i) + delete[] _items[i].data; + delete[] _items; +} + +//-------------------------------------------------------------------------- + +const char *FabInputExceededError = "FabDecompressor - Passed end of input buffer during decompression"; +const char *FabOutputExceededError = "FabDecompressor - Decompressed data exceeded specified size"; + +void FabDecompressor::decompress(const byte *srcData, int srcSize, byte *destData, int destSize) { + byte copyLen, copyOfsShift, copyOfsMask, copyLenMask; + unsigned long copyOfs; + byte *destP; + + // Validate that the data starts with the FAB header + if (strncmp((const char *)srcData, "FAB", 3) != 0) + error("FabDecompressor - Invalid compressed data"); + + int shiftVal = srcData[3]; + if ((shiftVal < 10) || (shiftVal > 13)) + error("FabDecompressor - Invalid shift start"); + + copyOfsShift = 16 - shiftVal; + copyOfsMask = 0xFF << (shiftVal - 8); + copyLenMask = (1 << copyOfsShift) - 1; + copyOfs = 0xFFFF0000; + destP = destData; + + // Initialise data fields + _srcData = srcData; + _srcP = _srcData + 6; + _srcSize = srcSize; + _bitsLeft = 16; + _bitBuffer = READ_LE_UINT16(srcData + 4); + + for (;;) { + if (getBit() == 0) { + if (getBit() == 0) { + copyLen = ((getBit() << 1) | getBit()) + 2; + copyOfs = *_srcP++ | 0xFFFFFF00; + } else { + copyOfs = (((_srcP[1] >> copyOfsShift) | copyOfsMask) << 8) | _srcP[0]; + copyLen = _srcP[1] & copyLenMask; + _srcP += 2; + if (copyLen == 0) { + copyLen = *_srcP++; + if (copyLen == 0) + break; + else if (copyLen == 1) + continue; + else + copyLen++; + } else { + copyLen += 2; + } + copyOfs |= 0xFFFF0000; + } + while (copyLen-- > 0) { + if (destP - destData == destSize) + error(FabOutputExceededError); + + *destP = destP[(signed int)copyOfs]; + destP++; + } + } else { + if (_srcP - srcData == srcSize) + error(FabInputExceededError); + if (destP - destData == destSize) + error(FabOutputExceededError); + + *destP++ = *_srcP++; + } + } + + if (destP - destData != destSize) + error("FabDecompressor - Decompressed data does not match header decompressed size"); +} + +int FabDecompressor::getBit() { + _bitsLeft--; + if (_bitsLeft == 0) { + if (_srcP - _srcData == _srcSize) + error(FabInputExceededError); + + _bitBuffer = (READ_LE_UINT16(_srcP) << 1) | (_bitBuffer & 1); + _srcP += 2; + _bitsLeft = 16; + } + + int bit = _bitBuffer & 1; + _bitBuffer >>= 1; + return bit; +} + +} // End of namespace M4 diff --git a/engines/mads/compression.h b/engines/mads/compression.h new file mode 100644 index 0000000000..bf690dcc46 --- /dev/null +++ b/engines/mads/compression.h @@ -0,0 +1,80 @@ +/* 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 MADS_COMPRESSION_H +#define MADS_COMPRESSION_H + +#include "common/scummsys.h" +#include "common/endian.h" +#include "common/memstream.h" +#include "common/stream.h" + +#include "mads/mads.h" + +namespace MADS { + +struct MadsPackEntry { +public: + uint16 hash; + uint32 size; + uint32 compressedSize; + byte *data; +}; + +class MadsPack { +private: + MadsPackEntry *_items; + int _count; + int _dataOffset; + + void initialise(Common::SeekableReadStream *stream); +public: + static bool isCompressed(Common::SeekableReadStream *stream); + MadsPack(Common::SeekableReadStream *stream); + MadsPack(const Common::String &resourceName, MADSEngine *_vm); + ~MadsPack(); + + int getCount() const { return _count; } + MadsPackEntry &getItem(int index) const { return _items[index]; } + MadsPackEntry &operator[](int index) const { return _items[index]; } + Common::MemoryReadStream *getItemStream(int index) { + return new Common::MemoryReadStream(_items[index].data, _items[index].size, + DisposeAfterUse::NO); + } + int getDataOffset() const { return _dataOffset; } +}; + +class FabDecompressor { +private: + int _bitsLeft; + uint32 _bitBuffer; + const byte *_srcData, *_srcP; + int _srcSize; + + int getBit(); +public: + void decompress(const byte *srcData, int srcSize, byte *destData, int destSize); +}; + +} // End of namespace MADS + +#endif diff --git a/engines/mads/detection.cpp b/engines/mads/detection.cpp index 4e56655f40..73a4b97931 100644 --- a/engines/mads/detection.cpp +++ b/engines/mads/detection.cpp @@ -38,8 +38,19 @@ namespace MADS { struct MADSGameDescription { ADGameDescription desc; + + int gameID; + uint32 features; }; +uint32 MADSEngine::getGameID() const { + return _gameDescription->gameID; +} + +uint32 MADSEngine::getGameFeatures() const { + return _gameDescription->gameID; +} + uint32 MADSEngine::getFeatures() const { return _gameDescription->desc.flags; } @@ -52,10 +63,6 @@ Common::Platform MADSEngine::getPlatform() const { return _gameDescription->desc.platform; } -bool MADSEngine::getIsDemo() const { - return _gameDescription->desc.flags & ADGF_DEMO; -} - } // End of namespace MADS static const PlainGameDescriptor MADSGames[] = { @@ -165,7 +172,7 @@ SaveStateDescriptor MADSMetaEngine::querySaveMetaInfos(const char *target, int s #if PLUGIN_ENABLED_DYNAMIC(MADS) -REGISTER_PLUGIN_DYNAMIC(MADS, PLUGIN_TYPE_ENGINE, MADSMetaEngine); + REGISTER_PLUGIN_DYNAMIC(MADS, PLUGIN_TYPE_ENGINE, MADSMetaEngine); #else -REGISTER_PLUGIN_STATIC(MADS, PLUGIN_TYPE_ENGINE, MADSMetaEngine); + REGISTER_PLUGIN_STATIC(MADS, PLUGIN_TYPE_ENGINE, MADSMetaEngine); #endif diff --git a/engines/mads/events.cpp b/engines/mads/events.cpp new file mode 100644 index 0000000000..8d6262aec3 --- /dev/null +++ b/engines/mads/events.cpp @@ -0,0 +1,34 @@ +/* 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/scummsys.h" +#include "common/events.h" +#include "mads/mads.h" +#include "mads/events.h" + +namespace MADS { + +EventsManager::EventsManager(MADSEngine *vm) { + _vm = vm; +} + +} // End of namespace MADS diff --git a/engines/mads/events.h b/engines/mads/events.h new file mode 100644 index 0000000000..ea52c7ab9c --- /dev/null +++ b/engines/mads/events.h @@ -0,0 +1,43 @@ +/* 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 MADS_EVENTS_H +#define MADS_EVENTS_H + +#include "common/scummsys.h" + +namespace MADS { + +class MADSEngine; + +class EventsManager { +private: + MADSEngine *_vm; +public: + EventsManager(MADSEngine *vm); + + void handleEvents() { /* TODO */ } +}; + +} // End of namespace MADS + +#endif /* MADS_EVENTS_H */ diff --git a/engines/mads/mads.cpp b/engines/mads/mads.cpp index 25730fa9e4..9998bc02e9 100644 --- a/engines/mads/mads.cpp +++ b/engines/mads/mads.cpp @@ -20,35 +20,57 @@ * */ -#include "mads/mads.h" -#include "mads/sound.h" #include "common/scummsys.h" #include "common/config-manager.h" #include "common/debug-channels.h" -#include "engines/util.h" #include "common/events.h" +#include "engines/util.h" +#include "mads/mads.h" +#include "mads/resources.h" +#include "mads/sound.h" +#include "mads/msurface.h" +#include "mads/msprite.h" namespace MADS { -MADSEngine *g_vm; - MADSEngine::MADSEngine(OSystem *syst, const MADSGameDescription *gameDesc) : - Engine(syst), _randomSource("MADS") { - DebugMan.addDebugChannel(kDebugPath, "Path", "Pathfinding debug level"); - DebugMan.addDebugChannel(kDebugScripts, "scripts", "Game scripts"); + _gameDescription(gameDesc), Engine(syst), _randomSource("MADS") { + + // Initialise fields + _easyMouse = true; + _invObjectStill = false; + _textWindowStill = false; + _palette = nullptr; + _resources = nullptr; + _screen = nullptr; + _sound = nullptr; } MADSEngine::~MADSEngine() { + delete _events; + delete _resources; + delete _screen; + delete _sound; } void MADSEngine::initialise() { - _soundManager.setVm(this, _mixer); + // Set up debug channels + DebugMan.addDebugChannel(kDebugPath, "Path", "Pathfinding debug level"); + DebugMan.addDebugChannel(kDebugScripts, "scripts", "Game scripts"); + + // Initial sub-system engine references + MSurface::setVm(this); + MSprite::setVm(this); + + _events = new EventsManager(this); + _resources = new ResourcesManager(this); + _screen = MSurface::init(); + _sound = new SoundManager(this, _mixer); } Common::Error MADSEngine::run() { initGraphics(320, 200, false); initialise(); - _soundManager.test(); Common::Event e; while (!shouldQuit()) { diff --git a/engines/mads/mads.h b/engines/mads/mads.h index b54c46ea96..8ca181ea02 100644 --- a/engines/mads/mads.h +++ b/engines/mads/mads.h @@ -30,6 +30,9 @@ #include "common/util.h" #include "engines/engine.h" #include "graphics/surface.h" +#include "mads/events.h" +#include "mads/msurface.h" +#include "mads/resources.h" #include "mads/sound.h" /** @@ -46,13 +49,22 @@ namespace MADS { #define DEBUG_INTERMEDIATE 2 #define DEBUG_DETAILED 3 -#define MAX_RESOLVE 1000 - enum MADSDebugChannels { kDebugPath = 1 << 0, kDebugScripts = 1 << 1 }; +enum { + GType_RexNebular = 0, + GType_DragonSphere = 1, + GType_Phantom = 2, + GType_Riddle = 3 +}; + +enum { + GF_MADS = 1 << 0, + GF_M4 = 1 << 1 +}; struct MADSGameDescription; @@ -61,13 +73,26 @@ class MADSEngine : public Engine { private: const MADSGameDescription *_gameDescription; Common::RandomSource _randomSource; - SoundManager _soundManager; + bool _easyMouse; + bool _invObjectStill; + bool _textWindowStill; + + /** + * Handles basic initialisation + */ void initialise(); protected: // Engine APIs virtual Common::Error run(); virtual bool hasFeature(EngineFeature f) const; +public: + EventsManager *_events; + Palette *_palette; + ResourcesManager *_resources; + MSurface *_screen; + SoundManager *_sound; + public: MADSEngine(OSystem *syst, const MADSGameDescription *gameDesc); virtual ~MADSEngine(); @@ -76,7 +101,8 @@ public: Common::Language getLanguage() const; Common::Platform getPlatform() const; uint16 getVersion() const; - bool getIsDemo() const; + uint32 getGameID() const; + uint32 getGameFeatures() const; int getRandomNumber(int maxNumber); }; diff --git a/engines/mads/module.mk b/engines/mads/module.mk index d8a26a2704..7ac919f246 100644 --- a/engines/mads/module.mk +++ b/engines/mads/module.mk @@ -1,10 +1,17 @@ MODULE := engines/mads MODULE_OBJS := \ + compression.o \ detection.o \ + events.o \ + mads.o \ + msprite.o \ + msurface.o \ + palette.o \ + resources.o \ sound.o \ sound_nebular.o \ - mads.o + sprite.o # This module can be built as a plugin ifeq ($(ENABLE_MADS), DYNAMIC_PLUGIN) diff --git a/engines/mads/msprite.cpp b/engines/mads/msprite.cpp new file mode 100644 index 0000000000..60c22d8c06 --- /dev/null +++ b/engines/mads/msprite.cpp @@ -0,0 +1,207 @@ +/* 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/scummsys.h" +#include "engines/util.h" +#include "graphics/palette.h" +#include "mads/mads.h" +#include "mads/msurface.h" +#include "mads/msprite.h" + +namespace MADS { + +enum { + kEndOfLine = 0, + kEndOfSprite = 1, + kMarker = 2 +}; + +MADSEngine *MSprite::_vm; + +MSprite *MSprite::init(MSurface &s) { + if (_vm->getGameFeatures() & GF_MADS) { + return new MSpriteMADS(s); + } else { + return new MSpriteM4(s); + } +} + +MSprite *MSprite::init(Common::SeekableReadStream *source, const Common::Point &offset, + int widthVal, int heightVal, bool decodeRle, uint8 encodingVal) { + + if (_vm->getGameFeatures() & GF_MADS) { + return new MSpriteMADS(source, offset, widthVal, heightVal, decodeRle, encodingVal); + } else { + return new MSpriteM4(source, offset, widthVal, heightVal, decodeRle, encodingVal); + } +} + +MSprite::MSprite(MSurface &s): _surface(s) { + _encoding = 0; +} + +MSprite::MSprite(Common::SeekableReadStream *source, const Common::Point &offset, + int widthVal, int heightVal, bool decodeRle, uint8 encodingVal) + : _surface(*MSurface::init(widthVal, heightVal)), + _encoding(encodingVal), _offset(offset) { + + // Load the sprite data + load(source, widthVal, heightVal, decodeRle); +} + +MSprite::~MSprite() { +} + +/*------------------------------------------------------------------------*/ + +void MSpriteMADS::load(Common::SeekableReadStream *stream, int widthVal, int heightVal, + bool decodeRle) { + loadSprite(stream); +} + +// TODO: The sprite outlines (pixel value 0xFD) are not shown +void MSpriteMADS::loadSprite(Common::SeekableReadStream *source) { + byte *outp, *lineStart; + bool newLine = false; + + outp = _surface.getData(); + lineStart = _surface.getData(); + + while (1) { + byte cmd1, cmd2, count, pixel; + + if (newLine) { + outp = lineStart + _surface.w; + lineStart = outp; + newLine = false; + } + + cmd1 = source->readByte(); + + if (cmd1 == 0xFC) + break; + else if (cmd1 == 0xFF) + newLine = true; + else if (cmd1 == 0xFD) { + while (!newLine) { + count = source->readByte(); + if (count == 0xFF) { + newLine = true; + } else { + pixel = source->readByte(); + while (count--) + *outp++ = (pixel == 0xFD) ? 0 : pixel; + } + } + } else { + while (!newLine) { + cmd2 = source->readByte(); + if (cmd2 == 0xFF) { + newLine = true; + } else if (cmd2 == 0xFE) { + count = source->readByte(); + pixel = source->readByte(); + while (count--) + *outp++ = (pixel == 0xFD) ? 0 : pixel; + } else { + *outp++ = (cmd2 == 0xFD) ? 0 : cmd2; + } + } + } + } +} + +/*------------------------------------------------------------------------*/ + +void MSpriteM4::load(Common::SeekableReadStream *stream, int widthVal, int heightVal, + bool decodeRle) { + if (decodeRle) { + loadRle(stream); + } else { + // Raw sprite data, load directly + byte *dst = _surface.getData(); + stream->read(dst, widthVal * heightVal); + } +} + +void MSpriteM4::loadRle(Common::SeekableReadStream* rleData) { + byte *dst = _surface.getData(); + for (;;) { + byte len = rleData->readByte(); + if (len == 0) { + len = rleData->readByte(); + if (len <= kMarker) { + if (len == kEndOfSprite) + break; + } else { + while (len--) { + *dst++ = rleData->readByte(); + } + } + } else { + byte value = rleData->readByte(); + while (len--) + *dst++ = value; + } + } +} + +void MSpriteM4::loadDeltaRle(Common::SeekableReadStream* rleData, int destX, int destY) { + int lineNum = 0; + byte *dst = _surface.getBasePtr(destX, destY); + + for (;;) { + byte len = rleData->readByte(); + if (len == 0) { + len = rleData->readByte(); + if (len <= kMarker) { + if (len == kEndOfLine) { + dst = _surface.getBasePtr(destX, destY + lineNum); + lineNum++; + } else if (len == kEndOfSprite) + break; + } else { + while (len--) { + byte pixel = rleData->readByte(); + if (pixel == 0) + dst++; + else + *dst++ = pixel; + /* NOTE: The change below behaved differently than the old code, + so I put the old code back in again above. + If the pixel value is 0, nothing should be written to the + output buffer, since 0 means transparent. */ + //*dst++ = (pixel == 0xFD) ? 0 : pixel; + } + } + } else { + byte value = rleData->readByte(); + if (value == 0) + dst += len; + else + while (len--) + *dst++ = value; + } + } +} + +} // End of namespace MADS diff --git a/engines/mads/msprite.h b/engines/mads/msprite.h new file mode 100644 index 0000000000..c49aac4fba --- /dev/null +++ b/engines/mads/msprite.h @@ -0,0 +1,152 @@ +/* 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 MADS_MSPRITE_H +#define MADS_MSPRITE_H + +#include "common/scummsys.h" +#include "mads/msurface.h" + +namespace MADS { + +class MADSEngine; + +struct BGR8 { + uint8 b, g, r; +}; + +typedef struct { + int32 x; // x position relative to GrBuff(0, 0) + int32 y; // y position relative to GrBuff(0, 0) + int32 scale_x; // x scale factor (can be negative for reverse draw) + int32 scale_y; // y scale factor (can't be negative) + uint8* depth_map; // depth code array for destination (doesn't care if srcDepth is 0) + BGR8* Pal; // palette for shadow draw (doesn't care if SHADOW bit is not set in Src.encoding) + uint8* ICT; // Inverse Color Table (doesn't care if SHADOW bit is not set in Src.encoding) + uint8 depth; // depth code for source (0 if no depth processing) +} DrawRequestX; + +typedef struct +{ + uint32 Pack; + uint32 Stream; + long hot_x; + long hot_y; + uint32 Width; + uint32 Height; + uint32 Comp; + uint32 Reserved[8]; + uint8* data; +} RendCell; + +#define SS_HEADER_NUM_FIELDS 14 +struct SpriteSeriesHeader { + uint32 header; + uint32 size; + uint32 packing; + uint32 frameRate; + uint32 pixSpeed; + uint32 maxWidth; + uint32 maxHeight; + uint32 reserved3; + uint32 reserved4; + uint32 reserved5; + uint32 reserved6; + uint32 reserved7; + uint32 reserved8; + uint32 count; +}; + +#define SF_HEADER_NUM_FIELDS 15 +struct SpriteFrameHeader { + uint32 pack; + uint32 stream; + uint32 x; + uint32 y; + uint32 width; + uint32 height; + uint32 comp; + uint32 reserved1; + uint32 reserved2; + uint32 reserved3; + uint32 reserved4; + uint32 reserved5; + uint32 reserved6; + uint32 reserved7; + uint32 reserved8; +}; + +class MSprite { +public: + MSprite *init(MSurface &s); + MSprite *init(Common::SeekableReadStream *source, const Common::Point &offset, int widthVal, + int heightVal, bool decodeRle = true, uint8 encodingVal = 0); +protected: + static MADSEngine *_vm; + + MSprite(MSurface &s); + MSprite(Common::SeekableReadStream *source, const Common::Point &offset, + int widthVal, int heightVal, bool decodeRle = true, uint8 encodingVal = 0); + + virtual void load(Common::SeekableReadStream *stream, int widthVal, int heightVal, bool decodeRle) {} +public: + static void setVm(MADSEngine *vm) { _vm = vm; } + virtual ~MSprite(); + + MSurface &_surface; + Common::Point _pos; + Common::Point _offset; + uint8 _encoding; +}; + +class MSpriteMADS: public MSprite { + friend class MSprite; +private: + void loadSprite(Common::SeekableReadStream *source); +protected: + MSpriteMADS(MSurface &s): MSprite(s) {} + MSpriteMADS(Common::SeekableReadStream *source, const Common::Point &offset, + int widthVal, int heightVal, bool decodeRle = true, uint8 encodingVal = 0): + MSprite(source, offset, widthVal, heightVal, decodeRle, encodingVal) {} + + virtual void load(Common::SeekableReadStream *stream, int widthVal, int heightVal, bool decodeRle); +}; + +class MSpriteM4: public MSprite { + friend class MSprite; +private: + // Loads a sprite from the given stream, and optionally decompresses the RLE-encoded data + // Loads an RLE compressed sprite; the surface must have been created before + void loadRle(Common::SeekableReadStream *rleData); + void loadDeltaRle(Common::SeekableReadStream *rleData, int destX, int destY); +protected: + MSpriteM4(MSurface &s): MSprite(s) {} + MSpriteM4(Common::SeekableReadStream *source, const Common::Point &offset, + int widthVal, int heightVal, bool decodeRle = true, uint8 encodingVal = 0): + MSprite(source, offset, widthVal, heightVal, decodeRle, encodingVal) {} + + virtual void load(Common::SeekableReadStream *stream, int widthVal, int heightVal, bool decodeRle); +}; + +} // End of namespace MADS + +#endif /* MADS_MSPRITE_H */ diff --git a/engines/mads/msurface.cpp b/engines/mads/msurface.cpp new file mode 100644 index 0000000000..810f9326f7 --- /dev/null +++ b/engines/mads/msurface.cpp @@ -0,0 +1,690 @@ +/* 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 "engines/util.h" +#include "mads/mads.h" +#include "mads/compression.h" +#include "mads/msurface.h" +#include "mads/msprite.h" + +namespace MADS { + +MADSEngine *MSurface::_vm = nullptr; + +MSurface *MSurface::init(bool isScreen) { + if (_vm->getGameID() == GType_RexNebular) { + return new MSurfaceNebular(isScreen); + } else if (_vm->getGameFeatures() & GF_MADS) { + return new MSurfaceMADS(isScreen); + } else { + return new MSurfaceM4(isScreen); + } +} + +MSurface *MSurface::init(int w, int h) { + if (_vm->getGameID() == GType_RexNebular) { + return new MSurfaceNebular(w, h); + } else if (_vm->getGameFeatures() & GF_MADS) { + return new MSurfaceMADS(w, h); + } else { + return new MSurfaceM4(w, h); + } +} + +MSurface::MSurface(bool isScreen) { + create(g_system->getWidth(), g_system->getHeight()); + _isScreen = isScreen; +} + +MSurface::MSurface(int Width, int Height) { + create(Width, Height); + _isScreen = false; +} + +void MSurface::vLine(int x, int y1, int y2) { + Graphics::Surface::vLine(x, y1, y2, _color); +} + +void MSurface::hLine(int x1, int x2, int y) { + Graphics::Surface::hLine(x1, y, x2, _color); +} + +void MSurface::vLineXor(int x, int y1, int y2) { + // Clipping + if (x < 0 || x >= w) + return; + + if (y2 < y1) + SWAP(y2, y1); + + if (y1 < 0) + y1 = 0; + if (y2 >= h) + y2 = h - 1; + + byte *ptr = (byte *)getBasePtr(x, y1); + while (y1++ <= y2) { + *ptr ^= 0xFF; + ptr += pitch; + } + +} + +void MSurface::hLineXor(int x1, int x2, int y) { + // Clipping + if (y < 0 || y >= h) + return; + + if (x2 < x1) + SWAP(x2, x1); + + if (x1 < 0) + x1 = 0; + if (x2 >= w) + x2 = w - 1; + + if (x2 < x1) + return; + + byte *ptr = (byte *)getBasePtr(x1, y); + while (x1++ <= x2) + *ptr++ ^= 0xFF; + +} + +void MSurface::line(int x1, int y1, int x2, int y2, byte color) { + Graphics::Surface::drawLine(x1, y1, x2, y2, color); +} + + +void MSurface::frameRect(int x1, int y1, int x2, int y2) { + Graphics::Surface::frameRect(Common::Rect(x1, y1, x2, y2), _color); +} + +void MSurface::fillRect(int x1, int y1, int x2, int y2) { + Graphics::Surface::fillRect(Common::Rect(x1, y1, x2, y2), _color); +} + +int MSurface::scaleValue(int value, int scale, int err) { + int scaled = 0; + while (value--) { + err -= scale; + while (err < 0) { + scaled++; + err += 100; + } + } + return scaled; +} + +void MSurface::drawSprite(int x, int y, SpriteInfo &info, const Common::Rect &clipRect) { + + enum { + kStatusSkip, + kStatusScale, + kStatusDraw + }; + + // NOTE: The current clipping code assumes that the top left corner of the clip + // rectangle is always 0, 0 + assert(clipRect.top == 0 && clipRect.left == 0); + + // TODO: Put err* and scaled* into SpriteInfo + int errX = info.hotX * info.scaleX % 100; + int errY = info.hotY * info.scaleY % 100; + int scaledWidth = scaleValue(info.width, info.scaleX, errX); + int scaledHeight = scaleValue(info.height, info.scaleY, errY); + + /* + printf("MSurface::drawSprite() info.width = %d; info.scaleX = %d; info.height = %d; info.scaleY = %d; scaledWidth = %d; scaledHeight = %d\n", + info.width, info.scaleX, info.height, info.scaleY, scaledWidth, scaledHeight); fflush(stdout); + */ + + int clipX = 0, clipY = 0; + // Clip the sprite's width and height according to the clip rectangle's dimensions + // This clips the sprite to the bottom and right + if (x >= 0) { + scaledWidth = MIN(x + scaledWidth, clipRect.right) - x; + } else { + clipX = x; + scaledWidth = x + scaledWidth; + } + if (y >= 0) { + scaledHeight = MIN(y + scaledHeight, clipRect.bottom) - y; + } else { + clipY = y; + scaledHeight = y + scaledHeight; + } + + //printf("MSurface::drawSprite() width = %d; height = %d; scaledWidth = %d; scaledHeight = %d\n", info.width, info.height, scaledWidth, scaledHeight); fflush(stdout); + + // Check if sprite is inside the screen. If it's not, there's no need to draw it + if (scaledWidth + x <= 0 || scaledHeight + y <= 0) // check left and top (in case x,y are negative) + return; + if (scaledWidth <= 0 || scaledHeight <= 0) // check right and bottom + return; + int heightAmt = scaledHeight; + + byte *src = info.sprite->_surface.getData(); + byte *dst = getBasePtr(x - info.hotX - clipX, y - info.hotY - clipY); + + int status = kStatusSkip; + byte *scaledLineBuf = new byte[scaledWidth]; + + while (heightAmt > 0) { + + if (status == kStatusSkip) { + // Skip line + errY -= info.scaleY; + if (errY < 0) + status = kStatusScale; + else + src += info.width; + } else { + + if (status == kStatusScale) { + // Scale current line + byte *lineDst = scaledLineBuf; + int curErrX = errX; + int widthVal = scaledWidth; + byte *tempSrc = src; + int startX = clipX; + while (widthVal > 0) { + byte pixel = *tempSrc++; + curErrX -= info.scaleX; + while (curErrX < 0) { + if (startX == 0) { + *lineDst++ = pixel; + widthVal--; + } else { + startX++; + } + curErrX += 100; + } + } + src += info.width; + status = kStatusDraw; + } + + if (status == kStatusDraw && clipY == 0) { + // Draw previously scaled line + // TODO Implement different drawing types (depth, shadow etc.) + byte *tempDst = dst; + for (int lineX = 0; lineX < scaledWidth; lineX++) { + byte pixel = scaledLineBuf[lineX]; + + if (info.encoding & 0x80) { + + if (pixel == 0x80) { + pixel = 0; + } else { + byte destPixel = *tempDst; + byte r, g, b; + r = CLIP((info.palette[destPixel].r * pixel) >> 10, 0, 31); + g = CLIP((info.palette[destPixel].g * pixel) >> 10, 0, 31); + b = CLIP((info.palette[destPixel].b * pixel) >> 10, 0, 31); + pixel = info.inverseColorTable[(b << 10) | (g << 5) | r]; + } + } + + if (pixel) + *tempDst = pixel; + + tempDst++; + } + dst += pitch; + heightAmt--; + // TODO depth etc. + //depthAddress += Destination -> Width; + + errY += 100; + if (errY >= 0) + status = kStatusSkip; + } else if (status == kStatusDraw && clipY < 0) { + clipY++; + + errY += 100; + if (errY >= 0) + status = kStatusSkip; + } + + } + + } + + delete[] scaledLineBuf; + +} + +// Surface methods + +byte *MSurface::getData() { + return (byte *)Graphics::Surface::getPixels(); +} + +byte *MSurface::getBasePtr(int x, int y) { + return (byte *)Graphics::Surface::getBasePtr(x, y); +} + +void MSurface::freeData() { +} + +void MSurface::empty() { + Common::fill(getBasePtr(0, 0), getBasePtr(w, h), _vm->_palette->BLACK); +} + +void MSurface::frameRect(const Common::Rect &r, uint8 color) { + Graphics::Surface::frameRect(r, color); +} + +void MSurface::fillRect(const Common::Rect &r, uint8 color) { + Graphics::Surface::fillRect(r, color); +} + +void MSurface::copyFrom(MSurface *src, const Common::Rect &srcBounds, int destX, int destY, + int transparentColor) { + // Validation of the rectangle and position + if ((destX >= w) || (destY >= h)) + return; + + Common::Rect copyRect = srcBounds; + if (destX < 0) { + copyRect.left += -destX; + destX = 0; + } else if (destX + copyRect.width() > w) { + copyRect.right -= destX + copyRect.width() - w; + } + if (destY < 0) { + copyRect.top += -destY; + destY = 0; + } else if (destY + copyRect.height() > h) { + copyRect.bottom -= destY + copyRect.height() - h; + } + + if (!copyRect.isValidRect()) + return; + + // Copy the specified area + + byte *data = src->getData(); + byte *srcPtr = data + (src->width() * copyRect.top + copyRect.left); + byte *destPtr = (byte *)pixels + (destY * width()) + destX; + + for (int rowCtr = 0; rowCtr < copyRect.height(); ++rowCtr) { + if (transparentColor == -1) + // No transparency, so copy line over + Common::copy(srcPtr, srcPtr + copyRect.width(), destPtr); + else { + // Copy each byte one at a time checking for the transparency color + for (int xCtr = 0; xCtr < copyRect.width(); ++xCtr) + if (srcPtr[xCtr] != transparentColor) destPtr[xCtr] = srcPtr[xCtr]; + } + + srcPtr += src->width(); + destPtr += width(); + } + + src->freeData(); +} + +#undef COL_TRANS + +void MSurface::translate(RGBList *list, bool isTransparent) { + byte *p = getBasePtr(0, 0); + byte *palIndexes = list->palIndexes(); + + for (int i = 0; i < width() * height(); ++i, ++p) { + if (!isTransparent || (*p != 0)) { + assert(*p < list->size()); + *p = palIndexes[*p]; + } + } + + freeData(); +} + +/*------------------------------------------------------------------------*/ + +void MSurfaceMADS::loadCodes(Common::SeekableReadStream *source) { + if (!source) { + free(); + return; + } + + uint16 widthVal = 320; + uint16 heightVal = 156; + byte *walkMap = new byte[source->size()]; + + create(widthVal, heightVal); + source->read(walkMap, source->size()); + + byte *ptr = (byte *)getBasePtr(0, 0); + + for (int y = 0; y < heightVal; y++) { + for (int x = 0; x < widthVal; x++) { + int ofs = x + (y * widthVal); + if ((walkMap[ofs / 8] << (ofs % 8)) & 0x80) + *ptr++ = 1; // walkable + else + *ptr++ = 0; + } + } +} + +void MSurfaceMADS::loadBackground(int roomNumber, RGBList **palData) { + // clear previous data + empty(); + + // Get a MadsPack reference to the tile set and mapping + char resourceName[20]; + int i; + + // Uncompressed tile map resource + sprintf(resourceName, "rm%d.mm", roomNumber); + MadsPack tileMapFile(resourceName, _vm); + Common::SeekableReadStream *mapStream = tileMapFile.getItemStream(0); + + // Get the details of the tiles and map + mapStream->readUint32LE(); + int tileCountX = mapStream->readUint16LE(); + int tileCountY = mapStream->readUint16LE(); + int tileWidthMap = mapStream->readUint16LE(); + int tileHeightMap = mapStream->readUint16LE(); + int screenWidth = mapStream->readUint16LE(); + int screenHeight = mapStream->readUint16LE(); + int tileCountMap = tileCountX * tileCountY; + delete mapStream; + + // Obtain tile map information + typedef Common::List > TileSetList; + typedef TileSetList::iterator TileSetIterator; + TileSetList tileSet; + uint16 *tileMap = new uint16[tileCountMap]; + mapStream = tileMapFile.getItemStream(1); + for (i = 0; i < tileCountMap; ++i) + tileMap[i] = mapStream->readUint16LE(); + delete mapStream; + + _vm->_resources->toss(resourceName); + + // -------------------------------------------------------------------------------- + + // Tile map data, which needs to be kept compressed, as the tile offsets refer to + // the compressed data. Each tile is then uncompressed separately + sprintf(resourceName, "rm%d.tt", roomNumber); + Common::SeekableReadStream *tileDataComp = _vm->_resources->get(resourceName); + MadsPack tileData(tileDataComp); + Common::SeekableReadStream *tileDataUncomp = tileData.getItemStream(0); + + // Validate that the data matches between the tiles and tile map file and is valid + int tileCount = tileDataUncomp->readUint16LE(); + int tileWidth = tileDataUncomp->readUint16LE(); + int tileHeight = tileDataUncomp->readUint16LE(); + delete tileDataUncomp; + assert(tileCountMap == tileCount); + assert(tileWidth == tileWidthMap); + assert(tileHeight == tileHeightMap); + assert(screenWidth == _vm->_screen->width()); + assert(screenHeight <= _vm->_screen->height()); + + // -------------------------------------------------------------------------------- + + // Get the palette to use + tileDataUncomp = tileData.getItemStream(2); + // Set palette + if (!palData) { + _vm->_palette->setMadsPalette(tileDataUncomp, 4); + } else { + int numColors; + RGB8 *rgbList = _vm->_palette->decodeMadsPalette(tileDataUncomp, &numColors); + *palData = new RGBList(numColors, rgbList, true); + } + delete tileDataUncomp; + + // -------------------------------------------------------------------------------- + + // Get tile data + + tileDataUncomp = tileData.getItemStream(1); + FabDecompressor fab; + uint32 compressedTileDataSize = 0; + + for (i = 0; i < tileCount; i++) { + tileDataUncomp->seek(i * 4, SEEK_SET); + uint32 tileOfs = tileDataUncomp->readUint32LE(); + MSurface *newTile = MSurface::init(tileWidth, tileHeight); + + if (i == tileCount - 1) + compressedTileDataSize = tileDataComp->size() - tileOfs; + else + compressedTileDataSize = tileDataUncomp->readUint32LE() - tileOfs; + + //printf("Tile: %i, compressed size: %i\n", i, compressedTileDataSize); + + newTile->empty(); + + byte *compressedTileData = new byte[compressedTileDataSize]; + + tileDataComp->seek(tileData.getDataOffset() + tileOfs, SEEK_SET); + tileDataComp->read(compressedTileData, compressedTileDataSize); + + fab.decompress(compressedTileData, compressedTileDataSize, newTile->getData(), + tileWidth * tileHeight); + tileSet.push_back(TileSetList::value_type(newTile)); + delete[] compressedTileData; + } + + delete tileDataUncomp; + + // -------------------------------------------------------------------------------- + + // Loop through the mapping data to place the tiles on the screen + + uint16 *tIndex = &tileMap[0]; + for (int y = 0; y < tileCountY; y++) { + for (int x = 0; x < tileCountX; x++) { + int tileIndex = *tIndex++; + assert(tileIndex < tileCount); + TileSetIterator tile = tileSet.begin(); + for (i = 0; i < tileIndex; i++) + ++tile; + ((*tile).get())->copyTo(this, x * tileWidth, y * tileHeight); + } + } + tileSet.clear(); + _vm->_resources->toss(resourceName); +} + +void MSurfaceMADS::loadInterface(int index, RGBList **palData) { + char resourceName[20]; + sprintf(resourceName, "i%d.int", index); + MadsPack intFile(resourceName, _vm); + RGB8 *palette = new RGB8[16]; + + // Chunk 0, palette + Common::SeekableReadStream *intStream = intFile.getItemStream(0); + + for (int i = 0; i < 16; i++) { + palette[i].r = intStream->readByte() << 2; + palette[i].g = intStream->readByte() << 2; + palette[i].b = intStream->readByte() << 2; + intStream->readByte(); + intStream->readByte(); + intStream->readByte(); + } + *palData = new RGBList(16, palette, true); + delete intStream; + + // Chunk 1, data + intStream = intFile.getItemStream(1); + create(320, 44); + intStream->read(pixels, 320 * 44); + delete intStream; +} + +/*------------------------------------------------------------------------*/ + +void MSurfaceNebular::loadBackground(int roomNumber, RGBList **palData) { + // clear previous data + empty(); + + Common::String resourceName = Common::String::format("rm%d.art", roomNumber); + Common::SeekableReadStream *stream = _vm->_resources->get(resourceName); + loadBackgroundStream(stream, palData); + + _vm->_resources->toss(resourceName); +} + +void MSurfaceNebular::loadBackgroundStream(Common::SeekableReadStream *source, RGBList **palData) { + MadsPack packData(source); + Common::MemoryReadStream *sourceUnc = packData.getItemStream(0); + + int sceneWidth = sourceUnc->readUint16LE(); + int sceneHeight = sourceUnc->readUint16LE(); + int sceneSize = sceneWidth * sceneHeight; + if (sceneWidth > this->width()) { + warning("Background width is %i, too large to fit in screen. Setting it to %i", sceneWidth, this->width()); + sceneWidth = this->width(); + sceneSize = sceneWidth * sceneHeight; + } + if (sceneHeight > this->height()) { + warning("Background height is %i, too large to fit in screen.Setting it to %i", sceneHeight, this->height()); + sceneHeight = this->height(); + sceneSize = sceneWidth * sceneHeight; + } + + // Set palette + if (!palData) { + _vm->_palette->setMadsPalette(sourceUnc, 4); + } else { + int numColors; + RGB8 *rgbList = _vm->_palette->decodeMadsPalette(sourceUnc, &numColors); + *palData = new RGBList(numColors, rgbList, true); + } + delete sourceUnc; + + // Get the raw data for the background + sourceUnc = packData.getItemStream(1); + assert((int)sourceUnc->size() >= sceneSize); + + byte *pData = (byte *)pixels; + sourceUnc->read(pData, sceneSize); + + freeData(); + delete sourceUnc; +} + +/*------------------------------------------------------------------------*/ + +void MSurfaceM4::loadCodes(Common::SeekableReadStream *source) { + if (!source) { + free(); + return; + } + + uint16 widthVal = source->readUint16LE(); + uint16 heightVal = source->readUint16LE(); + + create(widthVal, heightVal); + source->read(pixels, widthVal * heightVal); +} + +void MSurfaceM4::loadBackground(int roomNumber, RGBList **palData) { + if (palData) + *palData = NULL; + Common::String resourceName = Common::String::format("%i.tt", roomNumber); + Common::SeekableReadStream *stream = _vm->_resources->get(resourceName); + loadBackgroundStream(stream); + + _vm->_resources->toss(resourceName); +} + +void MSurfaceM4::loadBackgroundStream(Common::SeekableReadStream *source) { + MSurface *tileBuffer = MSurface::init(); + uint curTileX = 0, curTileY = 0; + int clipX = 0, clipY = 0; + RGB8 palette[256]; + + source->skip(4); + /*uint32 size =*/ source->readUint32LE(); + uint32 widthVal = source->readUint32LE(); + uint32 heightVal = source->readUint32LE(); + uint32 tilesX = source->readUint32LE(); + uint32 tilesY = source->readUint32LE(); + uint32 tileWidth = source->readUint32LE(); + uint32 tileHeight = source->readUint32LE(); + uint8 blackIndex = 0; + + // BGR data, which is converted to RGB8 + for (uint i = 0; i < 256; i++) { + palette[i].b = source->readByte() << 2; + palette[i].g = source->readByte() << 2; + palette[i].r = source->readByte() << 2; + palette[i].u = source->readByte() << 2; + + if ((blackIndex == 0) && !palette[i].r && !palette[i].g && !palette[i].b) + blackIndex = i; + } + + _vm->_palette->setPalette(palette, 0, 256); + + // resize or create the surface + // Note that the height of the scene in game scenes is smaller than the screen height, + // as the bottom part of the screen is the inventory + assert(width() == (int)widthVal); + + tileBuffer->create(tileWidth, tileHeight); + + for (curTileY = 0; curTileY < tilesY; curTileY++) { + clipY = MIN(heightVal, (1 + curTileY) * tileHeight) - (curTileY * tileHeight); + + for (curTileX = 0; curTileX < tilesX; curTileX++) { + clipX = MIN(widthVal, (1 + curTileX) * tileWidth) - (curTileX * tileWidth); + + // Read a tile and copy it to the destination surface + source->read(tileBuffer->getData(), tileWidth * tileHeight); + Common::Rect srcBounds(0, 0, clipX, clipY); + copyFrom(tileBuffer, srcBounds, curTileX * tileWidth, curTileY * tileHeight); + } + } + + if (heightVal < (uint)height()) + fillRect(Common::Rect(0, heightVal, width(), height()), blackIndex); + + delete tileBuffer; +} + +/*------------------------------------------------------------------------*/ + +void MSurfaceRiddle::loadBackground(const Common::String &sceneName) { + char resourceName[20]; + Common::SeekableReadStream *stream; + // Loads a Riddle scene + Common::String resName = Common::String::format("%s.tt", sceneName.c_str()); + stream = _vm->_resources->get(resourceName); + + loadBackgroundStream(stream); + + _vm->_resources->toss(resourceName); +} + +} // End of namespace MADS diff --git a/engines/mads/msurface.h b/engines/mads/msurface.h new file mode 100644 index 0000000000..9bb651b02b --- /dev/null +++ b/engines/mads/msurface.h @@ -0,0 +1,185 @@ +/* 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 MADS_MSURFACE_H +#define MADS_MSURFACE_H + +#include "common/scummsys.h" +#include "common/rect.h" +#include "graphics/surface.h" +#include "mads/palette.h" + +namespace MADS { + +class MADSEngine; +class MSprite; + +struct SpriteInfo { + MSprite *sprite; + int hotX, hotY; + int width, height; + int scaleX, scaleY; + uint8 encoding; + byte *inverseColorTable; + RGB8 *palette; +}; + +class MSurface : public Graphics::Surface { +public: + static MADSEngine *_vm; + + /** + * Sets the engine reference + */ + static void setVm(MADSEngine *vm) { _vm = vm; } + + /** + * Create a new surface the same size as the screen. + * @param isScreen Set to true for the screen surface + */ + static MSurface *init(bool isScreen = false); + + /** + * Create a surface + */ + static MSurface *init(int w, int h); +private: + byte _color; + bool _isScreen; +protected: + MSurface(bool isScreen = false); + MSurface(int w, int h); +public: + void create(int w, int h) { + Graphics::Surface::create(w, h, Graphics::PixelFormat::createFormatCLUT8()); + } + + void setColor(byte value) { _color = value; } + byte getColor() { return _color; } + void vLine(int x, int y1, int y2); + void hLine(int x1, int x2, int y); + void vLineXor(int x, int y1, int y2); + void hLineXor(int x1, int x2, int y); + void line(int x1, int y1, int x2, int y2, byte color); + void frameRect(int x1, int y1, int x2, int y2); + void fillRect(int x1, int y1, int x2, int y2); + + static int scaleValue(int value, int scale, int err); + void drawSprite(int x, int y, SpriteInfo &info, const Common::Rect &clipRect); + + // Surface methods + int width() { return w; } + int height() { return h; } + void setSize(int sizeX, int sizeY); + byte *getData(); + byte *getBasePtr(int x, int y); + void freeData(); + void empty(); + void frameRect(const Common::Rect &r, uint8 color); + void fillRect(const Common::Rect &r, uint8 color); + void copyFrom(MSurface *src, const Common::Rect &srcBounds, int destX, int destY, + int transparentColor = -1); + + void update() { + if (_isScreen) { + g_system->copyRectToScreen((const byte *)pixels, pitch, 0, 0, w, h); + g_system->updateScreen(); + } + } + + // copyTo methods + void copyTo(MSurface *dest, int transparentColor = -1) { + dest->copyFrom(this, Common::Rect(width(), height()), 0, 0, transparentColor); + } + void copyTo(MSurface *dest, int x, int y, int transparentColor = -1) { + dest->copyFrom(this, Common::Rect(width(), height()), x, y, transparentColor); + } + void copyTo(MSurface *dest, const Common::Rect &srcBounds, int destX, int destY, + int transparentColor = -1) { + dest->copyFrom(this, srcBounds, destX, destY, transparentColor); + } + + void translate(RGBList *list, bool isTransparent = false); + + // Base virtual methods + virtual void loadBackground(const Common::String &sceneName) {} + virtual void loadBackground(int roomNumber, RGBList **palData) = 0; + virtual void loadBackground(Common::SeekableReadStream *source, RGBList **palData) {} + virtual void loadCodes(Common::SeekableReadStream *source) = 0; + virtual void loadInterface(int index, RGBList **palData) {} +}; + +class MSurfaceMADS: public MSurface { + friend class MSurface; +protected: + MSurfaceMADS(bool isScreen = false): MSurface(isScreen) {} + MSurfaceMADS(int w, int h): MSurface(w, h) {} +public: + virtual void loadCodes(Common::SeekableReadStream *source); + virtual void loadBackground(const Common::String &sceneName) {} + virtual void loadBackground(int roomNumber, RGBList **palData); + virtual void loadInterface(int index, RGBList **palData); +}; + +class MSurfaceNebular: public MSurfaceMADS { + friend class MSurface; +protected: + MSurfaceNebular(bool isScreen = false): MSurfaceMADS(isScreen) {} + MSurfaceNebular(int w, int h): MSurfaceMADS(w, h) {} +private: + void loadBackgroundStream(Common::SeekableReadStream *source, RGBList **palData); +public: + virtual void loadBackground(int roomNumber, RGBList **palData); +}; + +class MSurfaceM4: public MSurface { + friend class MSurface; +protected: + MSurfaceM4(bool isScreen = false): MSurface(isScreen) {} + MSurfaceM4(int w, int h): MSurface(w, h) {} + + void loadBackgroundStream(Common::SeekableReadStream *source); +public: + virtual void loadCodes(Common::SeekableReadStream *source); + virtual void loadBackground(int roomNumber, RGBList **palData); +}; + +class MSurfaceRiddle: public MSurfaceM4 { + friend class MSurface; +protected: + MSurfaceRiddle(bool isScreen = false): MSurfaceM4(isScreen) {} + MSurfaceRiddle(int w, int h): MSurfaceM4(w, h) {} +public: + virtual void loadBackground(const Common::String &sceneName); +}; +/* + void rexLoadBackground(Common::SeekableReadStream *source, RGBList **palData = NULL); + void madsLoadBackground(int roomNumber, RGBList **palData = NULL); + void m4LoadBackground(Common::SeekableReadStream *source); + + void madsloadInterface(int index, RGBList **palData); + + */ + +} // End of namespace MADS + +#endif /* MADS_MSURFACE_H */ diff --git a/engines/mads/palette.cpp b/engines/mads/palette.cpp new file mode 100644 index 0000000000..cfd8568407 --- /dev/null +++ b/engines/mads/palette.cpp @@ -0,0 +1,289 @@ +/* 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/scummsys.h" +#include "engines/util.h" +#include "graphics/palette.h" +#include "mads/mads.h" +#include "mads/msurface.h" + +namespace MADS { + +RGBList::RGBList(int numEntries, RGB8 *srcData, bool freeData) { + _size = numEntries; + assert(numEntries <= 256); + + if (srcData == NULL) { + _data = new RGB8[numEntries]; + _freeData = true; + } else { + _data = srcData; + _freeData = freeData; + } + + _palIndexes = new byte[numEntries]; + Common::fill(&_palIndexes[0], &_palIndexes[numEntries], 0); +} + +RGBList::~RGBList() { + if (_freeData) + delete[] _data; + delete[] _palIndexes; +} + +/*------------------------------------------------------------------------*/ + +#define VGA_COLOR_TRANS(x) (x == 0x3f ? 255 : x << 2) + +Palette::Palette(MADSEngine *vm) : _vm(vm) { + reset(); + _fading_in_progress = false; + Common::fill(&_usageCount[0], &_usageCount[256], 0); +} + +void Palette::setPalette(const byte *colors, uint start, uint num) { + g_system->getPaletteManager()->setPalette(colors, start, num); + reset(); +} + +void Palette::setPalette(const RGB8 *colors, uint start, uint num) { + g_system->getPaletteManager()->setPalette((const byte *)colors, start, num); + reset(); +} + +void Palette::grabPalette(byte *colors, uint start, uint num) { + g_system->getPaletteManager()->grabPalette(colors, start, num); + reset(); +} + +uint8 Palette::palIndexFromRgb(byte r, byte g, byte b, RGB8 *paletteData) { + byte index = 0; + int32 minDist = 0x7fffffff; + RGB8 palData[256]; + int Rdiff, Gdiff, Bdiff; + + if (paletteData == NULL) { + g_system->getPaletteManager()->grabPalette((byte *)palData, 0, 256); + paletteData = &palData[0]; + } + + for (int palIndex = 0; palIndex < 256; ++palIndex) { + Rdiff = r - paletteData[palIndex].r; + Gdiff = g - paletteData[palIndex].g; + Bdiff = b - paletteData[palIndex].b; + + if (Rdiff * Rdiff + Gdiff * Gdiff + Bdiff * Bdiff < minDist) { + minDist = Rdiff * Rdiff + Gdiff * Gdiff + Bdiff * Bdiff; + index = (uint8)palIndex; + } + } + + return (uint8)index; +} + +void Palette::reset() { + RGB8 palData[256]; + g_system->getPaletteManager()->grabPalette((byte *)palData, 0, 256); + + BLACK = palIndexFromRgb(0, 0, 0, palData); + BLUE = palIndexFromRgb(0, 0, 255, palData); + GREEN = palIndexFromRgb(0, 255, 0, palData); + CYAN = palIndexFromRgb(0, 255, 255, palData); + RED = palIndexFromRgb(255, 0, 0, palData); + VIOLET = palIndexFromRgb(255, 0, 255, palData); + BROWN = palIndexFromRgb(168, 84, 84, palData); + LIGHT_GRAY = palIndexFromRgb(168, 168, 168, palData); + DARK_GRAY = palIndexFromRgb(84, 84, 84, palData); + LIGHT_BLUE = palIndexFromRgb(0, 0, 127, palData); + LIGHT_GREEN = palIndexFromRgb(0, 127, 0, palData); + LIGHT_CYAN = palIndexFromRgb(0, 127, 127, palData); + LIGHT_RED = palIndexFromRgb(84, 0, 0, palData); + PINK = palIndexFromRgb(84, 0, 0, palData); + YELLOW = palIndexFromRgb(0, 84, 84, palData); + WHITE = palIndexFromRgb(255, 255, 255, palData); +} + +void Palette::fadeIn(int numSteps, uint delayAmount, RGBList *destPalette) { + fadeIn(numSteps, delayAmount, destPalette->data(), destPalette->size()); +} + +void Palette::fadeIn(int numSteps, uint delayAmount, RGB8 *destPalette, int numColors) { + if (_fading_in_progress) + return; + + _fading_in_progress = true; + RGB8 blackPalette[256]; + Common::fill((byte *)&blackPalette[0], (byte *)&blackPalette[256], 0); + + // Initially set the black palette + _vm->_palette->setPalette(blackPalette, 0, numColors); + + // Handle the actual fading + fadeRange(blackPalette, destPalette, 0, numColors - 1, numSteps, delayAmount); + + _fading_in_progress = false; +} + +RGB8 *Palette::decodeMadsPalette(Common::SeekableReadStream *palStream, int *numColors) { + *numColors = palStream->readUint16LE(); + assert(*numColors <= 252); + + RGB8 *palData = new RGB8[*numColors]; + Common::fill((byte *)&palData[0], (byte *)&palData[*numColors], 0); + + for (int i = 0; i < *numColors; ++i) { + byte r = palStream->readByte(); + byte g = palStream->readByte(); + byte b = palStream->readByte(); + palData[i].r = VGA_COLOR_TRANS(r); + palData[i].g = VGA_COLOR_TRANS(g); + palData[i].b = VGA_COLOR_TRANS(b); + + // The next 3 bytes are unused + palStream->skip(3); + } + + return palData; +} + +int Palette::setMadsPalette(Common::SeekableReadStream *palStream, int indexStart) { + int colorCount; + RGB8 *palData = Palette::decodeMadsPalette(palStream, &colorCount); + _vm->_palette->setPalette(palData, indexStart, colorCount); + delete palData; + return colorCount; +} + +void Palette::setMadsSystemPalette() { + // Rex Nebular default system palette + resetColorCounts(); + + RGB8 palData[4]; + palData[0].r = palData[0].g = palData[0].b = 0; + palData[1].r = palData[1].g = palData[1].b = 0x54; + palData[2].r = palData[2].g = palData[2].b = 0xb4; + palData[3].r = palData[3].g = palData[3].b = 0xff; + + setPalette(palData, 0, 4); + blockRange(0, 4); +} + +void Palette::resetColorCounts() { + Common::fill(&_usageCount[0], &_usageCount[256], 0); +} + +void Palette::blockRange(int startIndex, int size) { + // Use a reference count of -1 to signal a palette index shouldn't be used + Common::fill(&_usageCount[startIndex], &_usageCount[startIndex + size], -1); +} + +void Palette::addRange(RGBList *list) { + RGB8 *data = list->data(); + byte *palIndexes = list->palIndexes(); + RGB8 palData[256]; + g_system->getPaletteManager()->grabPalette((byte *)&palData[0], 0, 256); + bool paletteChanged = false; + + for (int colIndex = 0; colIndex < list->size(); ++colIndex) { + // Scan through for an existing copy of the RGB value + int palIndex = -1; + while (++palIndex < 256) { + if (_usageCount[palIndex] <= 0) + // Palette index is to be skipped + continue; + + if ((palData[palIndex].r == data[colIndex].r) && + (palData[palIndex].g == data[colIndex].g) && + (palData[palIndex].b == data[colIndex].b)) + // Match found + break; + } + + if (palIndex == 256) { + // No match found, so find a free slot to use + palIndex = -1; + while (++palIndex < 256) { + if (_usageCount[palIndex] == 0) + break; + } + + if (palIndex == 256) + error("addRange - Ran out of palette space to allocate"); + + palData[palIndex].r = data[colIndex].r; + palData[palIndex].g = data[colIndex].g; + palData[palIndex].b = data[colIndex].b; + paletteChanged = true; + } + + palIndexes[colIndex] = palIndex; + ++_usageCount[palIndex]; + } + + if (paletteChanged) { + g_system->getPaletteManager()->setPalette((byte *)&palData[0], 0, 256); + reset(); + } +} + +void Palette::deleteRange(RGBList *list) { + // Release the reference count on each of the palette entries + for (int colIndex = 0; colIndex < list->size(); ++colIndex) { + int palIndex = list->palIndexes()[colIndex]; + assert(_usageCount[palIndex] > 0); + --_usageCount[palIndex]; + } +} + +void Palette::deleteAllRanges() { + for (int colIndex = 0; colIndex < 255; ++colIndex) + _usageCount[colIndex] = 0; +} + +void Palette::fadeRange(RGB8 *srcPal, RGB8 *destPal, int startIndex, int endIndex, + int numSteps, uint delayAmount) { + RGB8 tempPal[256]; + + // perform the fade + for(int stepCtr = 1; stepCtr <= numSteps; ++stepCtr) { + // Delay the specified amount + uint32 startTime = g_system->getMillis(); + while ((g_system->getMillis() - startTime) < delayAmount) { + _vm->_events->handleEvents(); + g_system->delayMillis(10); + } + + for (int i = startIndex; i <= endIndex; ++i) { + // Handle the intermediate rgb values for fading + tempPal[i].r = (byte) (srcPal[i].r + (destPal[i].r - srcPal[i].r) * stepCtr / numSteps); + tempPal[i].g = (byte) (srcPal[i].g + (destPal[i].g - srcPal[i].g) * stepCtr / numSteps); + tempPal[i].b = (byte) (srcPal[i].b + (destPal[i].b - srcPal[i].b) * stepCtr / numSteps); + } + + _vm->_palette->setPalette(&tempPal[startIndex], startIndex, endIndex - startIndex + 1); + } + + // Make sure the end palette exactly matches what is wanted + _vm->_palette->setPalette(&destPal[startIndex], startIndex, endIndex - startIndex + 1); +} + +} // End of namespace MADS diff --git a/engines/mads/palette.h b/engines/mads/palette.h new file mode 100644 index 0000000000..ab03d8d20b --- /dev/null +++ b/engines/mads/palette.h @@ -0,0 +1,110 @@ +/* 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 MADS_PALETTE_H +#define MADS_PALETTE_H + +#include "common/scummsys.h" + +namespace MADS { + +class MADSEngine; + +struct RGB8 { + uint8 r, g, b, u; +}; + +class RGBList { +private: + int _size; + RGB8 *_data; + byte *_palIndexes; + bool _freeData; +public: + RGBList(int numEntries = 256, RGB8 *srcData = NULL, bool freeData = true); + ~RGBList(); + + RGB8 *data() { return _data; } + byte *palIndexes() { return _palIndexes; } + int size() { return _size; } +}; + +#define PALETTE_COUNT 256 + +class Palette { +private: + MADSEngine *_vm; + bool _colorsChanged; + bool _fading_in_progress; + byte _originalPalette[PALETTE_COUNT * 4]; + byte _fadedPalette[PALETTE_COUNT * 4]; + int _usageCount[PALETTE_COUNT]; + + void reset(); +public: + Palette(MADSEngine *vm); + + void setPalette(const byte *colors, uint start, uint num); + void setPalette(const RGB8 *colors, uint start, uint num); + void grabPalette(byte *colors, uint start, uint num); + void grabPalette(RGB8 *colors, uint start, uint num) { + grabPalette((byte *)colors, start, num); + } + uint8 palIndexFromRgb(byte r, byte g, byte b, RGB8 *paletteData = NULL); + + void fadeIn(int numSteps, uint delayAmount, RGB8 *destPalette, int numColors); + void fadeIn(int numSteps, uint delayAmount, RGBList *destPalette); + static RGB8 *decodeMadsPalette(Common::SeekableReadStream *palStream, int *numColors); + int setMadsPalette(Common::SeekableReadStream *palStream, int indexStart = 0); + void setMadsSystemPalette(); + void fadeRange(RGB8 *srcPal, RGB8 *destPal, int startIndex, int endIndex, + int numSteps, uint delayAmount); + + // Methods used for reference counting color usage + void resetColorCounts(); + void blockRange(int startIndex, int size); + void addRange(RGBList *list); + void deleteRange(RGBList *list); + void deleteAllRanges(); + + // Color indexes + uint8 BLACK; + uint8 BLUE; + uint8 GREEN; + uint8 CYAN; + uint8 RED; + uint8 VIOLET; + uint8 BROWN; + uint8 LIGHT_GRAY; + uint8 DARK_GRAY; + uint8 LIGHT_BLUE; + uint8 LIGHT_GREEN; + uint8 LIGHT_CYAN; + uint8 LIGHT_RED; + uint8 PINK; + uint8 YELLOW; + uint8 WHITE; +}; + +} // End of namespace MADS + +#endif /* MADS_PALETTE_H */ diff --git a/engines/mads/resources.cpp b/engines/mads/resources.cpp new file mode 100644 index 0000000000..27b94a9e55 --- /dev/null +++ b/engines/mads/resources.cpp @@ -0,0 +1,32 @@ +/* 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/scummsys.h" +#include "mads/resources.h" + +namespace MADS { + +ResourcesManager::ResourcesManager(MADSEngine *vm) { + _vm = vm; +} + +} // End of namespace MADS diff --git a/engines/mads/resources.h b/engines/mads/resources.h new file mode 100644 index 0000000000..6eee0eac88 --- /dev/null +++ b/engines/mads/resources.h @@ -0,0 +1,57 @@ +/* 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 MADS_RESOURCES_H +#define MADS_RESOURCES_H + +#include "common/scummsys.h" +#include "common/stream.h" + +namespace MADS { + +class MADSEngine; + +class ResourcesManager { +private: + MADSEngine *_vm; +public: + ResourcesManager(MADSEngine *vm); + + /** + * Return a named resource + */ + Common::SeekableReadStream *get(const Common::String &resourceName) { + // TODO + return nullptr; + } + + /** + * Release a previously loaded resource + */ + void toss(const Common::String &resourceName) { + // TODO + } +}; + +} // End of namespace MADS + +#endif /* MADS_RESOURCES_H */ diff --git a/engines/mads/sound.cpp b/engines/mads/sound.cpp index e3590f5ce7..46ba997198 100644 --- a/engines/mads/sound.cpp +++ b/engines/mads/sound.cpp @@ -27,7 +27,9 @@ namespace MADS { -SoundManager::SoundManager() { +SoundManager::SoundManager(MADSEngine *vm, Audio::Mixer *mixer) { + _vm = vm; + _mixer = mixer; _asound = nullptr; } @@ -35,11 +37,6 @@ SoundManager::~SoundManager() { delete _asound; } -void SoundManager::setVm(MADSEngine *vm, Audio::Mixer *mixer) { - _vm = vm; - _mixer = mixer; -} - void SoundManager::test() { _asound = new Nebular::ASound1(_mixer); _asound->command(5); diff --git a/engines/mads/sound.h b/engines/mads/sound.h index 20b56ec4a1..cbd6511518 100644 --- a/engines/mads/sound.h +++ b/engines/mads/sound.h @@ -38,10 +38,9 @@ private: Audio::Mixer *_mixer; Nebular::ASound *_asound; public: - SoundManager(); + SoundManager(MADSEngine *vm, Audio::Mixer *mixer); ~SoundManager(); - void setVm(MADSEngine *vm, Audio::Mixer *mixer); void test(); void poll(); }; diff --git a/engines/mads/sound_nebular.h b/engines/mads/sound_nebular.h index f9251c9329..11836e6559 100644 --- a/engines/mads/sound_nebular.h +++ b/engines/mads/sound_nebular.h @@ -33,10 +33,10 @@ namespace MADS { -namespace Nebular { - class SoundManager; +namespace Nebular { + /** * Represents the data for a channel on the Adlib */ -- cgit v1.2.3