aboutsummaryrefslogtreecommitdiff
path: root/engines/mads/scene_data.cpp
diff options
context:
space:
mode:
authorFilippos Karapetis2014-04-27 21:14:26 +0300
committerFilippos Karapetis2014-04-27 21:20:02 +0300
commit4eba5032d817ea32e3f2f7be52826c2e40471852 (patch)
tree9d80015ef162f2f994dc0da1b84c2fa3ace8de74 /engines/mads/scene_data.cpp
parent76950bf0ac210ecc31e798ce34de9a3f010371b2 (diff)
downloadscummvm-rg350-4eba5032d817ea32e3f2f7be52826c2e40471852.tar.gz
scummvm-rg350-4eba5032d817ea32e3f2f7be52826c2e40471852.tar.bz2
scummvm-rg350-4eba5032d817ea32e3f2f7be52826c2e40471852.zip
MADS: Add initial support for V2 backgrounds and hotspots
V2 games include Phantom and Dragonsphere. OUAF hasn't been tested yet
Diffstat (limited to 'engines/mads/scene_data.cpp')
-rw-r--r--engines/mads/scene_data.cpp267
1 files changed, 215 insertions, 52 deletions
diff --git a/engines/mads/scene_data.cpp b/engines/mads/scene_data.cpp
index 9f4d7d99ec..646106ee9a 100644
--- a/engines/mads/scene_data.cpp
+++ b/engines/mads/scene_data.cpp
@@ -26,7 +26,9 @@
#include "mads/compression.h"
#include "mads/screen.h"
#include "mads/resources.h"
+#include "mads/dragonsphere/dragonsphere_scenes.h"
#include "mads/nebular/nebular_scenes.h"
+#include "mads/phantom/phantom_scenes.h"
namespace MADS {
@@ -49,10 +51,12 @@ KernelMessage::KernelMessage() {
/*------------------------------------------------------------------------*/
-void ARTHeader::load(Common::SeekableReadStream *f) {
- // Read in dimensions of image
- _width = f->readUint16LE();
- _height = f->readUint16LE();
+void ARTHeader::load(Common::SeekableReadStream *f, bool isV2) {
+ if (!isV2) {
+ // Read in dimensions of image
+ _width = f->readUint16LE();
+ _height = f->readUint16LE();
+ }
// Read in palette information
int palCount = f->readUint16LE();
@@ -91,11 +95,18 @@ void SceneInfo::SpriteInfo::load(Common::SeekableReadStream *f) {
/*------------------------------------------------------------------------*/
SceneInfo *SceneInfo::init(MADSEngine *vm) {
- if (vm->getGameID() == GType_RexNebular) {
+ switch (vm->getGameID()) {
+ case GType_RexNebular:
return new Nebular::SceneInfoNebular(vm);
- } else {
- error("Unknown game");
+ case GType_Dragonsphere:
+ return new Dragonsphere::SceneInfoDragonsphere(vm);
+ case GType_Phantom:
+ return new Phantom::SceneInfoPhantom(vm);
+ default:
+ error("SceneInfo: Unknown game");
}
+
+ return nullptr;
}
void SceneInfo::load(int sceneId, int variant, const Common::String &resName,
@@ -116,12 +127,25 @@ void SceneInfo::load(int sceneId, int variant, const Common::String &resName,
// Read in basic data
Common::SeekableReadStream *infoStream = infoPack.getItemStream(0);
- _sceneId = infoStream->readUint16LE();
+ if (_vm->getGameID() == GType_RexNebular) {
+ _sceneId = infoStream->readUint16LE();
+ } else {
+ infoStream->skip(6); // actual scene ID (string)
+ _sceneId = sceneId;
+ }
+
+ // TODO: The following isn't quite right for V2 games (it's all 0)
_artFileNum = infoStream->readUint16LE();
_depthStyle = infoStream->readUint16LE();
_width = infoStream->readUint16LE();
_height = infoStream->readUint16LE();
+ // HACK for V2 games (for now)
+ if (_vm->getGameID() != GType_RexNebular && _width == 0) {
+ _width = 320;
+ _height = 156;
+ }
+
infoStream->skip(24);
int nodeCount = infoStream->readUint16LE();
@@ -157,12 +181,15 @@ void SceneInfo::load(int sceneId, int variant, const Common::String &resName,
// Load in sprite draw information
Common::Array<SpriteInfo> spriteInfo;
- for (int i = 0; i < 50; ++i) {
- SpriteInfo info;
- info.load(infoStream);
-
- if (i < spriteInfoCount)
- spriteInfo.push_back(info);
+ // TODO: The following isn't quite right for V2 games
+ if (_vm->getGameID() == GType_RexNebular) {
+ for (int i = 0; i < 50; ++i) {
+ SpriteInfo info;
+ info.load(infoStream);
+
+ if (i < spriteInfoCount)
+ spriteInfo.push_back(info);
+ }
}
delete infoStream;
@@ -179,16 +206,67 @@ void SceneInfo::load(int sceneId, int variant, const Common::String &resName,
depthSurface.setSize(width, height);
}
- // Load the depth surface with the scene codes
- Common::SeekableReadStream *depthStream = infoPack.getItemStream(variant + 1);
- loadCodes(depthSurface, depthStream);
- delete depthStream;
+ if (_vm->getGameID() == GType_RexNebular) {
+ // Load the depth surface with the scene codes
+ Common::SeekableReadStream *depthStream = infoPack.getItemStream(variant + 1);
+ loadCodes(depthSurface, depthStream);
+ delete depthStream;
+ }
infoFile.close();
+ if (_vm->getGameID() == GType_RexNebular) {
+ loadMadsV1Background(sceneId, resName, flags, bgSurface);
+ loadPalette(sceneId, _artFileNum, resName, flags, bgSurface);
+ } else {
+ loadMadsV2Background(sceneId, resName, flags, bgSurface);
+ loadPalette(sceneId, sceneId, resName, flags, bgSurface);
+ }
+
+ Common::Array<SpriteAsset *> spriteSets;
+ Common::Array<int> usageList;
+
+ if (flags & 1) {
+ for (uint i = 0; i < setNames.size(); ++i) {
+ Common::String setResName;
+ if (sceneFlag || resName.hasPrefix("*"))
+ setResName += "*";
+ setResName += setNames[i];
+
+ SpriteAsset *sprites = new SpriteAsset(_vm, setResName, flags);
+ spriteSets.push_back(sprites);
+ usageList.push_back(sprites->_usageIndex);
+ }
+ }
+
+ _vm->_palette->_paletteUsage.updateUsage(usageList, _usageIndex);
+
+ for (uint i = 0; i < spriteInfo.size(); ++i) {
+ SpriteInfo &si = spriteInfo[i];
+ SpriteAsset *asset = spriteSets[si._spriteSetIndex];
+ assert(asset && _depthStyle != 2);
+
+ asset->drawScaled(asset->getCount(), depthSurface, bgSurface,
+ si._scale, si._depth, si._position);
+ }
+
+ // Free the sprite sets
+ for (int i = (int)spriteSets.size() - 1; i >= 0; --i) {
+ warning("TODO: sub_201C8 SPRITE_SET.field_6");
+ delete spriteSets[i];
+ }
+}
+
+void SceneInfo::loadPalette(int sceneId, int artFileNum, const Common::String &resName, int flags, MSurface &bgSurface) {
+ bool sceneFlag = sceneId >= 0;
+ Common::String resourceName;
+ bool isV2 = (_vm->getGameID() != GType_RexNebular);
+ Common::String extension = !isV2 ? ".ART" : ".TT";
+ int paletteStream = !isV2 ? 0 : 2;
+
// Get the ART resource
if (sceneFlag) {
- resourceName = Resources::formatName(RESPREFIX_RM, _artFileNum, ".ART");
+ resourceName = Resources::formatName(RESPREFIX_RM, artFileNum, extension);
} else {
resourceName = "*" + Resources::formatResource(resName, resName);
}
@@ -196,10 +274,10 @@ void SceneInfo::load(int sceneId, int variant, const Common::String &resName,
// Load in the ART header and palette
File artFile(resourceName);
MadsPack artResource(&artFile);
- Common::SeekableReadStream *stream = artResource.getItemStream(0);
+ Common::SeekableReadStream *stream = artResource.getItemStream(paletteStream);
ARTHeader artHeader;
- artHeader.load(stream);
+ artHeader.load(stream, isV2);
delete stream;
// Copy out the palette animation data
@@ -224,52 +302,137 @@ void SceneInfo::load(int sceneId, int variant, const Common::String &resName,
}
}
- // Read in the background surface data
- assert(_width == bgSurface.w && _height == bgSurface.h);
- stream = artResource.getItemStream(1);
- stream->read(bgSurface.getPixels(), bgSurface.w * bgSurface.h);
-
if (!(flags & 1)) {
// Translate the background to use the correct palette indexes
bgSurface.translate(artHeader._palette);
}
+}
+
+void SceneInfo::loadMadsV1Background(int sceneId, const Common::String &resName, int flags, MSurface &bgSurface) {
+ bool sceneFlag = sceneId >= 0;
+ Common::String resourceName;
+ Common::SeekableReadStream *stream;
+
+ // Get the ART resource
+ if (sceneFlag) {
+ resourceName = Resources::formatName(RESPREFIX_RM, _artFileNum, ".ART");
+ } else {
+ resourceName = "*" + Resources::formatResource(resName, resName);
+ }
+
+ // Load in the ART data
+ File artFile(resourceName);
+ MadsPack artResource(&artFile);
+
+ // Read in the background surface data
+ assert(_width == bgSurface.w && _height == bgSurface.h);
+ stream = artResource.getItemStream(1);
+ stream->read(bgSurface.getPixels(), bgSurface.w * bgSurface.h);
// Close the ART file
delete stream;
artFile.close();
+}
- Common::Array<SpriteAsset *> spriteSets;
- Common::Array<int> usageList;
-
- if (flags & 1) {
- for (uint i = 0; i < setNames.size(); ++i) {
- Common::String setResName;
- if (sceneFlag || resName.hasPrefix("*"))
- setResName += "*";
- setResName += setNames[i];
-
- SpriteAsset *sprites = new SpriteAsset(_vm, setResName, flags);
- spriteSets.push_back(sprites);
- usageList.push_back(sprites->_usageIndex);
- }
+void SceneInfo::loadMadsV2Background(int sceneId, const Common::String &resName, int flags, MSurface &bgSurface) {
+ Common::String tileMapResourceName = Resources::formatName(RESPREFIX_RM, sceneId, ".MM");
+ File tileMapFile(tileMapResourceName);
+ MadsPack tileMapPack(&tileMapFile);
+ Common::SeekableReadStream *mapStream = tileMapPack.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<Common::SharedPtr<MSurface> > TileSetList;
+ typedef TileSetList::iterator TileSetIterator;
+ TileSetList tileSet;
+ uint16 *tileMap = new uint16[tileCountMap];
+ mapStream = tileMapPack.getItemStream(1);
+ for (int i = 0; i < tileCountMap; ++i)
+ tileMap[i] = mapStream->readUint16LE();
+ delete mapStream;
+ tileMapFile.close();
+
+ // --------------------------------------------------------------------------------
+
+ // Tile data, which needs to be kept compressed, as the tile map offsets refer to
+ // the compressed data. Each tile is then uncompressed separately
+ Common::String tileDataResourceName = Resources::formatName(RESPREFIX_RM, sceneId, ".TT");
+ File tileDataFile(tileDataResourceName);
+ MadsPack tileDataPack(&tileDataFile);
+ Common::SeekableReadStream *tileDataUncomp = tileDataPack.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 == _width);
+ assert(screenHeight <= _height);
+
+ // --------------------------------------------------------------------------------
+
+ // Get tile data
+
+ tileDataUncomp = tileDataPack.getItemStream(1);
+ FabDecompressor fab;
+ uint32 compressedTileDataSize = 0;
+
+ for (int i = 0; i < tileCount; i++) {
+ tileDataUncomp->seek(i * 4, SEEK_SET);
+ uint32 tileOfs = tileDataUncomp->readUint32LE();
+ MSurface* newTile = new MSurface(tileWidth, tileHeight);
+
+ if (i == tileCount - 1)
+ compressedTileDataSize = tileDataFile.size() - tileOfs;
+ else
+ compressedTileDataSize = tileDataUncomp->readUint32LE() - tileOfs;
+
+ //debugCN(kDebugGraphics, "Tile: %i, compressed size: %i\n", i, compressedTileDataSize);
+
+ newTile->empty();
+
+ byte *compressedTileData = new byte[compressedTileDataSize];
+
+ tileDataFile.seek(tileDataPack.getDataOffset() + tileOfs, SEEK_SET);
+ tileDataFile.read(compressedTileData, compressedTileDataSize);
+
+ fab.decompress(compressedTileData, compressedTileDataSize, (byte*)newTile->getPixels(), tileWidth * tileHeight);
+ tileSet.push_back(TileSetList::value_type(newTile));
+ delete[] compressedTileData;
}
- _vm->_palette->_paletteUsage.updateUsage(usageList, _usageIndex);
+ delete tileDataUncomp;
- for (uint i = 0; i < spriteInfo.size(); ++i) {
- SpriteInfo &si = spriteInfo[i];
- SpriteAsset *asset = spriteSets[si._spriteSetIndex];
- assert(asset && _depthStyle != 2);
+ // --------------------------------------------------------------------------------
- asset->drawScaled(asset->getCount(), depthSurface, bgSurface,
- si._scale, si._depth, si._position);
- }
+ // Loop through the mapping data to place the tiles on the screen
- // Free the sprite sets
- for (int i = (int)spriteSets.size() - 1; i >= 0; --i) {
- warning("TODO: sub_201C8 SPRITE_SET.field_6");
- delete spriteSets[i];
+ 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 (int i = 0; i < tileIndex; i++)
+ ++tile;
+ ((*tile).get())->copyTo(&bgSurface, Common::Point(x * tileWidth, y * tileHeight));
+ }
}
+ tileSet.clear();
+ tileDataFile.close();
}
/*------------------------------------------------------------------------*/